package com.xbongbong.saas.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.paas.business.rule.RuleBusinessLogger;
import com.xbongbong.paas.constant.ConfigConstant;
import com.xbongbong.paas.constant.MessageConstant;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.constant.SizeConstant;
import com.xbongbong.paas.domain.entity.PaasFormDataEntity;
import com.xbongbong.paas.domain.entity.PaasFormExplainEntity;
import com.xbongbong.paas.domain.entity.PaasProcessDataEntity;
import com.xbongbong.paas.domain.entity.ext.ConditionsEntityExt;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.elasticsearch.model.PaasEsModel;
import com.xbongbong.paas.elasticsearch.model.PaasFormDataEsModel;
import com.xbongbong.paas.elasticsearch.pojo.vo.FormDataRepeatBatchVO;
import com.xbongbong.paas.elasticsearch.util.EsHelper;
import com.xbongbong.paas.elasticsearch.util.EsUtil;
import com.xbongbong.paas.elasticsearch.util.XbbElasticsearchRestTemplate;
import com.xbongbong.paas.enums.ConditionEnum;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.FlowStatusEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.enums.PaymentSheetTypeEnum;
import com.xbongbong.paas.enums.UnitEnum;
import com.xbongbong.paas.field.DefaultAttrPoJo;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.help.CommonHelp;
import com.xbongbong.paas.help.ProSaveHelp;
import com.xbongbong.paas.help.TransactionHelp;
import com.xbongbong.paas.log.MongoLogHelp;
import com.xbongbong.paas.log.constant.LogMemoConstant;
import com.xbongbong.paas.log.pojo.InfoArrPojo;
import com.xbongbong.paas.model.PaasFormExplainModel;
import com.xbongbong.paas.model.PaasProcessDataModel;
import com.xbongbong.paas.pojo.AddMuchFieldPojo;
import com.xbongbong.paas.pojo.FieldAttrEntityForImport;
import com.xbongbong.paas.pojo.FormTitlePoJo;
import com.xbongbong.paas.pojo.IdNamePojo;
import com.xbongbong.paas.pojo.SummaryDataPoJo;
import com.xbongbong.paas.pojo.dto.AddBatchDTO;
import com.xbongbong.paas.pojo.dto.FormDataAddDTO;
import com.xbongbong.paas.pojo.dto.FormDataDeleteBatchDTO;
import com.xbongbong.paas.pojo.dto.FormDataListDTO;
import com.xbongbong.paas.pojo.dto.FormDataUpdateGetDTO;
import com.xbongbong.paas.pojo.dto.ImportFormDataDTO;
import com.xbongbong.paas.pojo.dto.SaasFormSaveDTO;
import com.xbongbong.paas.pojo.dto.ValidateDataDTO;
import com.xbongbong.paas.pojo.imports.CellTitlePojo;
import com.xbongbong.paas.pojo.imports.CellValuePojo;
import com.xbongbong.paas.pojo.imports.RowGroupPojo;
import com.xbongbong.paas.pojo.vo.AfterSaveVO;
import com.xbongbong.paas.pojo.vo.FormDataAddVO;
import com.xbongbong.paas.pojo.vo.PaasFormDataEsListVO;
import com.xbongbong.paas.service.PaasFormDataService;
import com.xbongbong.parent.interfaces.DynamicStrategy;
import com.xbongbong.paas.service.dynamic.crm.strategy.DynamicStrategyFactory;
import com.xbongbong.paas.service.dynamic.crm.strategy.PayDynamicStrategy;
import com.xbongbong.paas.service.team.TeamDataHelp;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.helper.PageHelper;
import com.xbongbong.paas.toolbox.util.Arith;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.toolbox.util.DateUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.paas.util.ExplainUtil;
import com.xbongbong.pro.applist.pojo.AppListPojo;
import com.xbongbong.pro.applist.pojo.vo.ListAppVO;
import com.xbongbong.pro.constant.BusinessConstant;
import com.xbongbong.pro.constant.ElasticConstant;
import com.xbongbong.pro.domain.entity.UpdateDataEntity;
import com.xbongbong.pro.dynamic.pojo.dto.DynamicDeleteDTO;
import com.xbongbong.pro.dynamic.pojo.dto.DynamicPayDTO;
import com.xbongbong.pro.dynamic.pojo.dto.DynamicSaveDTO;
import com.xbongbong.pro.enums.DistributorMarkEnum;
import com.xbongbong.pro.enums.SaasMarkEnum;
import com.xbongbong.pro.enums.errorcodes.InvoiceErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.PayPlanErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.PaymentErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.TemplateErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.UserTeamErrorCodeEnum;
import com.xbongbong.pro.enums.fund.enums.ModelTypeEnum;
import com.xbongbong.pro.enums.fund.enums.PeriodTypeEnum;
import com.xbongbong.pro.formdata.pojo.dto.FormDataRepeatBatchDTO;
import com.xbongbong.pro.formexplain.pojo.dto.HandlerExplainInLinkItemDTO;
import com.xbongbong.pro.fundset.pojo.PeriodFilterPojo;
import com.xbongbong.pro.listbatch.pojo.dto.AddLabelDTO;
import com.xbongbong.pro.log.pojo.dto.RuleBusinessLogDTO;
import com.xbongbong.pro.message.constant.PaymentPushConstant;
import com.xbongbong.pro.message.enums.PushTypeEnum;
import com.xbongbong.pro.message.help.PushHelper;
import com.xbongbong.pro.message.pojo.PushRefTypePojo;
import com.xbongbong.pro.message.pojo.dto.MessageRabbitMqDTO;
import com.xbongbong.pro.payment.pojo.dto.PaymentDTO;
import com.xbongbong.pro.payment.pojo.dto.PaymentDeleteBatchDTO;
import com.xbongbong.pro.payment.pojo.dto.PaymentEditAttrUpdateDTO;
import com.xbongbong.pro.payment.pojo.dto.PaymentInsertBatchDTO;
import com.xbongbong.pro.payment.pojo.dto.PaymentUpdateBatchDTO;
import com.xbongbong.pro.payment.pojo.dto.PaymentUpdateBatchMuchFieldDTO;
import com.xbongbong.pro.payment.pojo.dto.PaymentUpdateByBusinessRuleDTO;
import com.xbongbong.pro.payment.pojo.dto.PaymentUpdateDTO;
import com.xbongbong.pro.payment.pojo.dto.RelationshipGetDTO;
import com.xbongbong.pro.payment.pojo.vo.PaymentDeleteBatchVO;
import com.xbongbong.pro.payment.pojo.vo.PaymentInsertBatchVO;
import com.xbongbong.pro.payment.pojo.vo.PaymentUpdateBatchMuchFieldVO;
import com.xbongbong.pro.payment.pojo.vo.PaymentUpdateBatchVO;
import com.xbongbong.pro.payment.pojo.vo.PaymentUpdateByBusinessRuleVO;
import com.xbongbong.pro.payment.pojo.vo.PaymentVO;
import com.xbongbong.pro.payment.pojo.vo.RelationshipGetPojo;
import com.xbongbong.pro.payment.pojo.vo.RelationshipGetVO;
import com.xbongbong.pro.rabbitmq.producer.BaseProducer;
import com.xbongbong.pro.service.toolbox.elasticsearch.help.ProEsHelper;
import com.xbongbong.pro.service.toolbox.statistic.help.ChartQueryHelp;
import com.xbongbong.pro.service.toolbox.statistic.help.FormHelp;
import com.xbongbong.pro.sheet.pojo.AmountDetailGetPojo;
import com.xbongbong.pro.sheet.pojo.dto.SheetAmountDetailGetDTO;
import com.xbongbong.pro.sheet.pojo.dto.SheetDeleteHandleRelateDTO;
import com.xbongbong.pro.sheet.pojo.vo.HandleLinkInfoVO;
import com.xbongbong.pro.sheet.pojo.vo.SheetAmountDetailGetVO;
import com.xbongbong.pro.user.pojo.ReturnUserAndDepartmentPojo;
import com.xbongbong.pro.webdetail.pojo.dto.PaymentReturnDTO;
import com.xbongbong.saas.analytical.impl.PaymentValidateAnalyticalServiceImpl;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.ErrorMessageConstant;
import com.xbongbong.saas.constant.ParameterConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.CustomerStatementEntity;
import com.xbongbong.saas.domain.entity.InvoiceRelationshipEntity;
import com.xbongbong.saas.domain.entity.PaymentUserEntity;
import com.xbongbong.saas.domain.entity.UserTeamEntity;
import com.xbongbong.saas.domain.entity.ext.ContractEntityExt;
import com.xbongbong.saas.domain.entity.ext.PaymentEntityExt;
import com.xbongbong.saas.domain.entity.ext.PaymentSheetEntityExt;
import com.xbongbong.saas.enums.CompanyConfigEnum;
import com.xbongbong.saas.enums.CustomerStatementEnum;
import com.xbongbong.saas.enums.OperateModuleTypeEnum;
import com.xbongbong.saas.enums.OperateTypeEnum;
import com.xbongbong.saas.enums.PaymentLinkTypeEnum;
import com.xbongbong.saas.enums.RedundantTemplateTypeEnum;
import com.xbongbong.saas.enums.SheetAloneEnum;
import com.xbongbong.saas.enums.TagEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.base.PaymentBaseEnum;
import com.xbongbong.saas.enums.business.ContractEnum;
import com.xbongbong.saas.enums.business.CustomerManagementEnum;
import com.xbongbong.saas.enums.business.InvoiceEnum;
import com.xbongbong.saas.enums.business.PaymentEnum;
import com.xbongbong.saas.enums.business.PaymentSheetEnum;
import com.xbongbong.saas.enums.business.RefTypeEnum;
import com.xbongbong.saas.enums.dictionary.HasRedEnum;
import com.xbongbong.saas.enums.dictionary.PaymentStatusEnum;
import com.xbongbong.saas.help.FundHelp;
import com.xbongbong.saas.help.ImportHelper;
import com.xbongbong.saas.help.LogHandleHelp;
import com.xbongbong.saas.help.ReceivablesHelper;
import com.xbongbong.saas.help.SaasCustomerStatementHelper;
import com.xbongbong.saas.help.SaasDeleteHelp;
import com.xbongbong.saas.help.SaasSaveHelp;
import com.xbongbong.saas.help.SaasUpdateHelp;
import com.xbongbong.saas.help.fund.PaymentHelp;
import com.xbongbong.saas.help.workflow.PayAndPaymentSheetHelp;
import com.xbongbong.saas.model.ContractModel;
import com.xbongbong.saas.model.CustomerStatementModel;
import com.xbongbong.saas.model.IndexTypeModel;
import com.xbongbong.saas.model.InvoiceRelationshipModel;
import com.xbongbong.saas.model.PaymentModel;
import com.xbongbong.saas.model.PaymentSheetModel;
import com.xbongbong.saas.model.PaymentUserModel;
import com.xbongbong.saas.service.CustomerStatementService;
import com.xbongbong.saas.service.FundSetService;
import com.xbongbong.saas.service.InvoiceService;
import com.xbongbong.saas.service.PaymentService;
import com.xbongbong.saas.service.PaymentSheetService;
import com.xbongbong.saas.service.SaasDetailTabService;
import com.xbongbong.saas.service.UserTeamService;
import com.xbongbong.saas.service.toolbox.help.FundMoneyHelp;
import com.xbongbong.saas.service.toolbox.help.LogHelp;
import com.xbongbong.saas.service.toolbox.help.UserTeamHelp;
import com.xbongbong.saas.toolbox.help.FastJsonHelper;
import com.xbongbong.sys.domain.entity.CompanyConfigEntity;
import com.xbongbong.sys.domain.entity.UserEntity;
import com.xbongbong.sys.model.CompanyConfigModel;
import com.xbongbong.sys.model.UserModel;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import static com.xbongbong.saas.enums.business.PaymentEnum.REAL_AMOUNT;
import static com.xbongbong.saas.toolbox.help.FastJsonHelper.getDoubleOrDefaultFromFormData;
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;

/**
 * 回款业务实现
 *
 * @author feng.zheng
 * @version v1.0
 * @date 2019/1/22 15:11
 * @since v1.0
 */
@Service("paymentService")
public class PaymentServiceImpl implements PaymentService {

    private static final Logger LOG = LoggerFactory.getLogger(PaymentServiceImpl.class);

    @Resource
    private SaasSaveHelp saasSaveHelp;
    @Resource
    private SaasUpdateHelp saasUpdateHelp;
    @Resource
    private PaymentModel paymentModel;
    @Resource
    private MongoLogHelp mongoLogHelp;
    @Resource
    private PaasFormDataService paasFormDataService;
    @Resource
    private ContractModel contractModel;
    @Resource
    private PaymentSheetService paymentSheetService;
    @Resource
    private PaymentSheetModel paymentSheetModel;
    @Resource
    private EsHelper esHelper;
    @Resource
    private UserTeamService userTeamService;
    @Resource
    private SaasDetailTabService saasDetailTabService;
    @Resource
    private PaasEsModel paasEsModel;
    @Resource
    private XbbElasticsearchRestTemplate xbbElasticsearchRestTemplate;
    @Resource
    private PushHelper pushHelper;
    @Resource
    private BaseProducer baseProducer;
    @Resource
    private CommonHelp commonHelp;
    @Resource
    private PaasFormExplainModel paasFormExplainModel;
    @Resource
    private PaasProcessDataModel paasProcessDataModel;
    @Resource
    private SaasDeleteHelp saasDeleteHelp;
    @Resource
    private ProEsHelper proEsHelper;
    @Resource
    private UserModel userModel;
    @Resource
    private PaymentUserModel paymentUserModel;
    @Resource
    @Lazy
    private RuleBusinessLogger ruleBusinessLogger;
    @Resource
    private ImportHelper importHelper;
    @Resource
    private PaasFormDataEsModel paasFormDataEsModel;
    @Resource
    private InvoiceRelationshipModel invoiceRelationshipModel;
    @Resource
    private FormHelp formHelp;
    @Resource
    private InvoiceService invoiceService;
    @Resource
    private FundHelp fundHelp;
    @Resource
    private FundMoneyHelp fundMoneyHelp;
    @Resource
    private CustomerStatementService customerStatementService;
    @Resource
    private PaymentHelp paymentHelp;
    @Resource
    private LogHelp logHelp;
    @Resource
    private LogHandleHelp logHandleHelp;
    @Resource
    private PaymentValidateAnalyticalServiceImpl paymentAnalyticalService;
    @Resource
    private CompanyConfigModel companyConfigModel;
    @Resource
    private FundSetService fundSetService;
    @Resource
    private ReceivablesHelper receivablesHelper;
    @Resource
    private ChartQueryHelp chartQueryHelp;
    @Resource
    private CustomerStatementModel customerStatementModel;
    @Resource
    private PayAndPaymentSheetHelp payAndPaymentSheetHelp;
    @Resource
    private SaasCustomerStatementHelper saasCustomerStatementHelper;
    @Resource
    private IndexTypeModel indexTypeModel;
    @Resource
    private TeamDataHelp teamDataHelp;
    @Resource
    private UserTeamHelp userTeamHelp;
    @Resource
    private DynamicStrategyFactory dynamicStrategyFactory;
    @Resource
    private TransactionHelp transactionHelp;

    /**
     * 回款保存前saas特殊校验
     *
     * @param validateDataDTO saas特殊校验数据入参
     * @throws XbbException 业务异常
     * @author feng.zheng
     * @date 2019/1/18
     */
    @Override
    public void beforeSave(ValidateDataDTO validateDataDTO) throws XbbException {
        paymentAnalyticalService.beforeSave(validateDataDTO);
    }





    @Override
    public AddBatchDTO beforeSaveBatch(FormDataAddDTO formDataSaveDTO, boolean fromApproval) throws XbbException {
        //校验一下团队
        return paymentAnalyticalService.beforeSaveBatch(formDataSaveDTO, fromApproval);
    }

    /**
     * 回款保存后逻辑
     *
     * @param saasFormSaveDTO saas保存数据
     * @throws XbbException 业务异常
     * @author feng.zheng
     */
    @Override
    public AfterSaveVO afterSave(SaasFormSaveDTO saasFormSaveDTO) throws XbbException {
        boolean isNew = saasFormSaveDTO.getIsNew();
        AfterSaveVO afterSaveVO = new AfterSaveVO();
        PaasFormDataEntity newPaasFormDataEntity = saasFormSaveDTO.getNewPaasFormDataEntity();
        JSONObject newData = saasFormSaveDTO.getNewData();
        JSONObject oldData = saasFormSaveDTO.getOldData();
        Long originId  = FastJsonHelper.getLongOrDefaultFromFormData(newData,PaymentEnum.RECEIVABLES_ORIGIN_ID.getAttr(),0L);
        Integer isRed = FastJsonHelper.getIntegerOrDefaultFromFormData(newData,PaymentEnum.RECEIVABLE_IS_RED.getAttr(),0);
        Long dataId = saasFormSaveDTO.getDataId();
        String corpid = saasFormSaveDTO.getCorpid();
        if (isNew) {
            //新增应收款需要插入对账单
            PaasFormDataEntityExt paasFormDataEntityExt = new PaasFormDataEntityExt();
            BeanUtil.copyProperties(newPaasFormDataEntity,paasFormDataEntityExt);
            List<PaasFormDataEntityExt> paymentInsertList = Arrays.asList(paasFormDataEntityExt);
            saasCustomerStatementHelper.save(XbbRefTypeEnum.PAYMENT.getCode(), saasFormSaveDTO.getExplainMap(), paymentInsertList, saasFormSaveDTO.getDistributorMark());
            //红冲应收处理
            if(originId > 0L && Objects.equals(isRed,BasicConstant.ONE)){
                //更新原应收款
                PaymentEntityExt originPayment = paymentModel.getByKey(originId,saasFormSaveDTO.getCorpid());
                JSONObject originObject = originPayment.getData();
                Double unAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(originObject,PaymentEnum.UN_AMOUNT.getAttr(),0D);
                Double redAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(originObject,PaymentEnum.RED_AMOUNT.getAttr(),0D);
                //现在需要生成的应收金额
                Double amount = FastJsonHelper.getDoubleOrDefaultFromFormData(newData,PaymentEnum.AMOUNT.getAttr(),0D);
                //num_3 未收金额 = 应收款-实收金额-坏账金额-丨红冲应收丨
                // 未收金额最新、红冲应收最新
                Double newUnAmount = Arith.sub(unAmount, Math.abs(amount));
                Double newRedAmount = Arith.add(redAmount, amount);
                originObject.put(PaymentEnum.UN_AMOUNT.getAttr(), newUnAmount);
                originObject.put(PaymentEnum.RED_AMOUNT.getAttr(),newRedAmount);
                originObject.put(PaymentEnum.RECEIVABLE_HAS_RED.getAttr(),BasicConstant.ONE);
                //对原应收款的状态的修改
                Double planAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(originObject,PaymentEnum.AMOUNT.getAttr(),0D);
                String paymentStatus = handleStatus(planAmount, newUnAmount, 0d, newRedAmount);
                originObject.put(PaymentEnum.STATUS.getAttr(),paymentStatus);
                paymentModel.update(originPayment);
            }

            try {
                if (!Objects.equals(DistributorMarkEnum.DISTRIBUTOR.getCode(), saasFormSaveDTO.getDistributorMark())) {
                    DynamicStrategy dynamicStrategy = dynamicStrategyFactory.getDynamicStrategyByBusinessType(saasFormSaveDTO.getBusinessType());
                    transactionHelp.afterCommitOrCommitNow(p -> {
                        dynamicStrategy.save(DynamicSaveDTO.initDynamicSaveDTO(paasFormDataEntityExt.getId(), paasFormDataEntityExt.getFormId(), saasFormSaveDTO,
                                userModel.getByKeyIngoreDel(paasFormDataEntityExt.getCreatorId(), saasFormSaveDTO.getCorpid()), null));
                    });
                }
            } catch (Exception e) {
                LOG.error("应收款新建动态失败：", e);
            }
        }else if (Objects.nonNull(dataId)) {
            //代表是编辑或者覆盖导入, 需要更新tb_customer_statement表中对应的单据的更新时间
            BoolQueryBuilder boolQueryBuilder = chartQueryHelp.boolQueryBuilder4Base(corpid);
            boolQueryBuilder.filter(termQuery(CustomerStatementEnum.SYS_LONG_1.getAttr(), XbbRefTypeEnum.PAYMENT.getCode()));
            List<CustomerStatementEntity> result = formHelp.getFormListByIds4All(IndexTypeEnum.IDX_SAAS_CUSTOMER_STATEMENT,boolQueryBuilder, "sysLong2", Arrays.asList(dataId), null, CustomerStatementEntity.class);
            List<CustomerStatementEntity> finalResult = new ArrayList<>();
            if (CollectionsUtil.isNotEmpty(result)){
                result.forEach(customerStatementEntity -> {
                    //做一层优化，如果时间一致就不做更新了
                    //对账日期
                    Long checkingDate = customerStatementEntity.getData().getLong(CustomerStatementEnum.CHECKING_DATE.  getAttr());
                    //应收金额 num_4
                    Double amountReceivable = customerStatementEntity.getData().getDouble(CustomerStatementEnum.AMOUNT_RECEIVABLE.getAttr());
                    //应收金额   num_1
                    Double paymentAmount = newData.getDouble(PaymentEnum.AMOUNT.getAttr());
                    //预计回款日期
                    Long estimateTime = newData.getLong(PaymentEnum.ESTIMATE_TIME.getAttr());
                    if (!Objects.equals(newData.getLong(PaymentEnum.ESTIMATE_TIME.getAttr()), checkingDate)||!Objects.equals(paymentAmount,amountReceivable)) {
                        //编辑时更新应收金额
                        customerStatementEntity.getData().put(CustomerStatementEnum.AMOUNT_RECEIVABLE.getAttr(), paymentAmount);
                        customerStatementEntity.getData().put(CustomerStatementEnum.CHECKING_DATE.getAttr(), estimateTime);
                        customerStatementEntity.setUpdateTime(DateUtil.getNow());
                        finalResult.add(customerStatementEntity);
                    }
                });
            }
            if (CollectionsUtil.isNotEmpty(finalResult)) {
                customerStatementModel.updateBatch(finalResult, corpid);
            }
        }
        // 团队保存
        teamDataHelp.saveUserTeam(saasFormSaveDTO.getSaasNeedRedundantAttrPoJo(), saasFormSaveDTO.getNewPaasFormDataEntity().getId(), saasFormSaveDTO.getNewPaasFormDataEntity(), saasFormSaveDTO.getIsImport(), false);
       /* if (Objects.equals(newData.getString(PaymentEnum.STATUS.getAttr()), PaymentStatusEnum.RECEIVABLES.getCode())
        && !Objects.equals(newData.getString(PaymentEnum.STATUS.getAttr()), oldData.getString(PaymentEnum.STATUS.getAttr()))) {
            PaymentSheetSaveDTO paymentSheetSaveDTO = new PaymentSheetSaveDTO();
            BeanUtil.copyProperties(saasFormSaveDTO, paymentSheetSaveDTO);
            PaasFormEntityExt paasFormEntityExt = paasFormModel.getByBusinessType(XbbRefTypeEnum.PAYMENT_SHEET.getCode(), saasFormSaveDTO.getCorpid());
            BeanUtil.copyProperties(paasFormEntityExt, paymentSheetSaveDTO);
            paymentSheetSaveDTO.setFormId(paasFormEntityExt.getId());
            JSONObject sheetData = SaasDataInitHelp.initPaymentSheet();
            try {
                JSONArray paymentArr = new JSONArray();
                JSONObject paymentObj = new JSONObject();
                paymentObj.put(StringConstant.SAAS_LINK_BUSINESS_ID, newPaasFormDataEntity.getId());
                paymentObj.put(StringConstant.SAAS_LINK_BUSINESS_NAME, newPaasFormDataEntity.getSerialNo());
                paymentArr.add(paymentObj);
                SaasDataInitHelp.dataSetNotNull(sheetData,PaymentSheetEnum.PAYMENT.getAttr(), paymentArr);
                SaasDataInitHelp.dataSetNotNull(sheetData,PaymentSheetEnum.SHEET_NO.getAttr(),newPaasFormDataEntity.getSerialNo() + ".1");
                ReturnUserAndDepartmentPojo returnUserAndDepartmentPojo = new ReturnUserAndDepartmentPojo();
                returnUserAndDepartmentPojo.setId(newData.get(PaymentEnum.BELONGER.getAttr()));
                SaasDataInitHelp.dataSetNotNull(sheetData,PaymentSheetEnum.BELONG_ID.getAttr(), returnUserAndDepartmentPojo);
                SaasDataInitHelp.dataSetNotNull(sheetData,PaymentSheetEnum.AMOUNT.getAttr(), newData.get(PaymentEnum.AMOUNT.getAttr()));
                SaasDataInitHelp.dataSetNotNull(sheetData,PaymentSheetEnum.PAYMENT_TIME.getAttr(), newData.get(PaymentEnum.ESTIMATE_TIME.getAttr()));
                JSONObject itemPoJo = new JSONObject();
                itemPoJo.put(StringConstant.VALUE, newData.get(PaymentEnum.PAYMENT_METHOD.getAttr()));
                SaasDataInitHelp.dataSetNotNull(sheetData,PaymentSheetEnum.PAY_METHOD.getAttr(), itemPoJo);
                SaasDataInitHelp.dataSet(sheetData,PaymentSheetEnum.MEMO.getAttr(),newData.get(PaymentEnum.MEMO.getAttr()));
                sheetData.put(PaymentSheetEnum.REF_TYPE.getAttr(),XbbRefTypeEnum.CONTRACT.getCode());
            } catch (XbbException e) {
                e.printStackTrace();
            }
            paymentSheetSaveDTO.setFromEdit(1);
            paymentSheetSaveDTO.setDataList(sheetData);*/
//            FormDataAddVO formDataAddVO = paymentSheetService.add(paymentSheetSaveDTO);
//            afterSaveVO.setMsg(formDataAddVO.getMsg());
//            afterSaveVO.setCode(formDataAddVO.getCode());
//            if (Objects.equals(afterSaveVO.getCode(),PaasConstant.FORM_ADD_PROCESS_RETURN_CODE)){
//                if (!Objects.equals(newData.getString(PaymentEnum.STATUS.getAttr()),oldData.getString(PaymentEnum.STATUS.getAttr()))){
//                    JSONObject data = new JSONObject();
//                    data.put(PaymentEnum.STATUS.getAttr(),oldData.getString(PaymentEnum.STATUS.getAttr()));
//                    paymentModel.updateBatch(Collections.singletonList(ExplainUtil.getUpdateData(newPaasFormDataEntity.getId(),data,saasFormSaveDTO.getCorpid())),saasFormSaveDTO.getCorpid());
//                }
//            }
        return afterSaveVO;
    }



    @Override
    @Transactional(rollbackFor = Exception.class)
    public FormDataAddVO pay(PaymentDTO payMentDTO) throws XbbException {
        String loginUserName = payMentDTO.getLoginUserName();
        String corpid = payMentDTO.getCorpid();
        String userId = payMentDTO.getUserId();
        Long formId = payMentDTO.getFormId();
        // 审批兼容
        if (payMentDTO.getProcessCreatorId() != null) {
            userId = payMentDTO.getProcessCreatorId();
            UserEntity userEntity = userModel.getByKeyIngoreDel(userId, corpid);
            loginUserName = userEntity.getName();
        }

        FormDataAddVO formDataAddVO = new FormDataAddVO();
        // 批量新增流水号集合
        List<AddMuchFieldPojo> addBatchList = payMentDTO.getAddBatchList();
        List<String> addBatchSerialNoList= new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);

        // 开启严控模式后生成流水号
        PaasFormExplainEntity formExplainEntity = paasFormExplainModel.getByFormId(payMentDTO.getFormId(), payMentDTO.getCorpid());
        if (Objects.isNull(formExplainEntity)) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_EXPLAIN_NOT_EXIST);
        }
        Map<String, FieldAttrEntity> explainMap = ExplainUtil.getExplainMap(formExplainEntity.getExplains(), null);
        FieldAttrEntity fieldAttrEntity = explainMap.get(PaymentEnum.PAYMENT_NO.getAttr());
        if (Objects.nonNull(fieldAttrEntity)) {
            String serialNo = "";
            FormDataAddDTO formDataAddDTO = new FormDataAddDTO();
            BeanUtil.copyProperties(payMentDTO, formDataAddDTO);
            for (AddMuchFieldPojo addMuchFieldPojo : addBatchList) {
                if (Objects.equals(fieldAttrEntity.getStrictController(), BasicConstant.ONE) && Objects.isNull(addMuchFieldPojo.getSerialNo())) {
                    serialNo = saasSaveHelp.getSerialNo(serialNo, formDataAddDTO, corpid, fieldAttrEntity);
                    addMuchFieldPojo.setSerialNo(serialNo);
//                    addMuchFieldPojo.getData().put(PaymentEnum.PAYMENT_NO.getAttr(), serialNo);
                }
                addBatchSerialNoList.add(addMuchFieldPojo.getSerialNo());
            }
        }
        String addBatchSerialNoStr = StringUtils.join(addBatchSerialNoList, "，");
        // 批量更新流水号集合
        List<AddMuchFieldPojo> updateBatchList = payMentDTO.getUpdateBatchList();
        // 批量删除流水号集合
        List<AddMuchFieldPojo> delBatchList = payMentDTO.getDelBatchList();

        try {
            PaymentInsertBatchVO paymentInsertBatchVO = new PaymentInsertBatchVO();
            PaymentUpdateBatchMuchFieldVO paymentUpdateBatchMuchFieldVO = new PaymentUpdateBatchMuchFieldVO();
            // 删除逻辑
            //TODO 废弃
            if (Objects.nonNull(delBatchList) && !delBatchList.isEmpty()) {
                List<Long> idList = new ArrayList<>();
                for (AddMuchFieldPojo item : delBatchList) {
                    idList.add(item.getId());
                }
                PaymentDeleteBatchDTO paymentDeleteBatchDTO = new PaymentDeleteBatchDTO();
                BeanUtil.copyProperties(payMentDTO, paymentDeleteBatchDTO);
                paymentDeleteBatchDTO.setDataIdList(idList);
                //paymentDeleteBatchDTO.setStatus(PaymentStatusEnum.UN_RECEIVABLES.getCode());
                PaymentDeleteBatchVO paymentDeleteBatchVO = deleteBatch(paymentDeleteBatchDTO);
                if(Objects.isNull(paymentDeleteBatchVO)) {
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
                }else {
                    if(Objects.nonNull(paymentDeleteBatchVO.getErrorTypeList())){
                        StringBuilder errorMsg = new StringBuilder();
                        if(Objects.nonNull(paymentDeleteBatchVO.getErrorDataList())){
                            paymentDeleteBatchVO.getErrorDataList().forEach(msg ->{
                                errorMsg.append(msg+"、");
                            });
                            errorMsg.deleteCharAt(errorMsg.length()-1);
                        }
                        throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001,paymentDeleteBatchVO.getErrorDataMemo()+errorMsg.toString());
                    }
                }
            }

            // 插入数据
            if(Objects.nonNull(addBatchList) && !addBatchList.isEmpty()){
                PaymentInsertBatchDTO paymentInsertBatchDTO = new PaymentInsertBatchDTO();
                BeanUtil.copyProperties(payMentDTO, paymentInsertBatchDTO);
                paymentInsertBatchDTO.setDataList(addBatchList);
                paymentInsertBatchVO = insertBatch(paymentInsertBatchDTO,payMentDTO.getParentNew(), userId);
                // 记录日志
                List<PaasFormDataEntityExt> insertList = paymentInsertBatchVO.getInsertList();
                formDataAddVO.setInsertList(insertList);
                //获取当前处于什么模式
                Long modelType = fundSetService.getModelType(corpid,XbbRefTypeEnum.CRM);
                //只有手动创建应收模式才主动生成对账单（其他模式在生成应收时已同时生成对账单）
                if (Objects.equals(modelType,ModelTypeEnum.PLAN.getCode())) {
                    //生成对账单
                    receivablesHelper.creatStatement(payMentDTO, XbbRefTypeEnum.PAYMENT.getCode(), null, explainMap, formDataAddVO);
                }
                if(insertList.size() > 1){
                    String memo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_BATCH_ADD_FORM_DETAIL), loginUserName, XbbRefTypeEnum.PAYMENT.getName(), insertList.size());
                    List<InfoArrPojo> infoArrPojoList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    InfoArrPojo infoArrPojo = new InfoArrPojo();
                    infoArrPojo.setTitle(PaymentEnum.PAYMENT_NO.getAttrName());
                    infoArrPojo.setContent(addBatchSerialNoStr);
                    infoArrPojoList.add(infoArrPojo);
                    mongoLogHelp.buildLog4InfoArr(infoArrPojoList, corpid, userId, loginUserName, OperateModuleTypeEnum.PaymentManage, OperateTypeEnum.NEW,
                            "", "", memo, payMentDTO.getHttpHeader());
                } else if (Objects.equals(insertList.size(), 1)){
                    String memo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_ADD_WORK), loginUserName, XbbRefTypeEnum.PAYMENT.getName(), addBatchSerialNoStr);
                    mongoLogHelp.buildLog(corpid, userId, loginUserName, OperateModuleTypeEnum.PaymentManage, OperateTypeEnum.NEW,
                            insertList.get(0).getId().toString(), addBatchSerialNoStr, memo, payMentDTO.getHttpHeader());
                }
            }
            //更新数据
            if(Objects.nonNull(updateBatchList) && !updateBatchList.isEmpty()){
                PaymentUpdateBatchMuchFieldDTO paymentUpdateBatchMuchFieldDTO = new PaymentUpdateBatchMuchFieldDTO();
                BeanUtil.copyProperties(payMentDTO, paymentUpdateBatchMuchFieldDTO);
                paymentUpdateBatchMuchFieldDTO.setDataList(updateBatchList);
                paymentUpdateBatchMuchFieldVO = updateBatchMuchField(paymentUpdateBatchMuchFieldDTO, true, explainMap);
            }

            // 添加回款单
            /**
             * 资金管理一期改造之后不会存在付款计划等于已回款的计划状态，即:不会存在在付款计划新建的时候同时存在付款单，
             * 当然在下一步已经处理掉了存在付款单为空时的方式了,所以可以选择性的删除
             * 注释以下一行
             * @author chenshan
             * @Since 2019-11-04 11:01
             */
            //addPaymentSheet(payMentDTO, paymentInsertBatchVO, paymentUpdateBatchMuchFieldVO);
            // TODO 回款计划保存后逻辑缺失

            if (!Objects.equals(payMentDTO.getIsImport(), 1)) {
                List<PaasFormDataEntityExt> paymentEntityExts = paymentInsertBatchVO.getInsertList();
                if (paymentEntityExts != null) {
                    for (PaasFormDataEntityExt paymentEntityExt : paymentEntityExts) {
                        UserEntity userEntity = userModel.getByKeyIngoreDel(paymentEntityExt.getCreatorId(), paymentEntityExt.getCorpid());
                        Long dataId = paymentEntityExt.getId();
                        // 应收款新建消息推送
                        // 21220 【审批】合同和回款单都开启审批，合同订单的签订人离职后，对合同进行编辑，并新增回款单，进入合同审批时，提示：服务器开小差
                        if (Objects.nonNull(userEntity)) {
                            List<String> pushUserList = pushHelper.getUserIdListByPushSetRule(corpid, PushTypeEnum.PAYMENT_PLAN_ADD.getCode(), PushTypeEnum.PAYMENT_PLAN_ADD.getSubCode(), userEntity, paymentEntityExt);
                            PushRefTypePojo.Options options = new PushRefTypePojo.Options(paymentEntityExt.getAppId(), paymentEntityExt.getMenuId(), paymentEntityExt.getFormId(), dataId, Collections.singletonList(dataId), SaasMarkEnum.SAAS.getCode(), XbbRefTypeEnum.PAYMENT.getCode(), XbbRefTypeEnum.PAYMENT.getCode());
                            MessageRabbitMqDTO messageRabbitMqDTO = new MessageRabbitMqDTO(corpid, pushUserList, Collections.singletonList(dataId), 0, null, I18nMessageUtil.getMessage(PaymentPushConstant.PAYMENT_PLAN_ADD_TITLE), String.format(I18nMessageUtil.getMessage(PaymentPushConstant.PAYMENT_PLAN_ADD_CONTENT), userEntity.getName(), paymentEntityExt.getData().getString(PaymentEnum.CONTRACT_LINK_TEXT.getAttr())), null, options);
                            baseProducer.sendMessage(PushTypeEnum.PAYMENT_PLAN_ADD, messageRabbitMqDTO);
                        }
                    }
                }
            }

        } catch (XbbException e) {
            throw e;
        } catch (Exception e) {
            LOG.error("paymentServiceImpl.pay回款出错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        formDataAddVO.setMsg(I18nMessageUtil.getMessage(MessageConstant.FORM_ADD_RETURN_MSG));
        return formDataAddVO;
    }

    @Override
    public PaymentInsertBatchVO insertBatch(PaymentInsertBatchDTO paymentInsertBatchDTO, Boolean parentNew, String creatorId) throws XbbException {
        PaymentInsertBatchVO paymentInsertBatchVO = new PaymentInsertBatchVO();
        try {
            List<PaasFormDataEntityExt> paidForList = new ArrayList<>();
            List<PaasFormDataEntityExt> insertList = new ArrayList<>();
            String corpid = paymentInsertBatchDTO.getCorpid();
            List<PaymentEntityExt> formDataList = new ArrayList<>();
            Long modelType = fundSetService.getModelType(corpid, XbbRefTypeEnum.CRM);
            //主要用于绑定应收款与团队的信息，只有编号是唯一值，所以编号-》团队
            Map<String, AddMuchFieldPojo> serialTeamMap = new HashMap<>();
            paymentInsertBatchDTO.getDataList().forEach((item)->{
                PaymentEntityExt paymentEntityExt = new PaymentEntityExt();
                BeanUtil.copyProperties(item, paymentEntityExt);
                paymentEntityExt.setCorpid(corpid);
                paymentEntityExt.setAppId(paymentInsertBatchDTO.getAppId());
                paymentEntityExt.setMenuId(paymentInsertBatchDTO.getMenuId());
                paymentEntityExt.setFormId(paymentInsertBatchDTO.getFormId());
                JSONObject data = item.getData();
                data.put(PaymentEnum.UN_AMOUNT.getAttr(), data.getDouble(PaymentEnum.AMOUNT.getAttr()));
                String status = data.getString(PaymentEnum.STATUS.getAttr());
                if(PaymentStatusEnum.RECEIVABLES.getCode().equals(status)) {
                    data.put(PaymentEnum.REAL_PAY_TIME.getAttr(), data.get(PaymentEnum.ESTIMATE_TIME.getAttr()));
                    paidForList.add(paymentEntityExt);
                } else if(PaymentStatusEnum.UN_RECEIVABLES.getCode().equals(status)) {
                    data.remove(PaymentEnum.BELONGER.getAttr());
                }
                fundHelp.removeNotInMapping(data);
                paymentEntityExt.setData(data);
                paymentEntityExt.setCreatorId(creatorId);
                //TODO haibin.zhang 对于回款或者saas业务部门是否必要
                paymentEntityExt.setDepartmentId(1L);
                if (Objects.nonNull(item.getDepartmentId())) {
                    paymentEntityExt.setDepartmentId(item.getDepartmentId());
                }
                if (StringUtil.isNotEmpty(item.getOwnerId())) {
                    paymentEntityExt.setOwnerId(item.getOwnerId());
                } else {
                    paymentEntityExt.setOwnerId(creatorId);
                }
                paymentEntityExt.setFlowStatus(FlowStatusEnum.NOT_NEED_APPROVAL.getType());
                long now = DateUtil.getInt();
                paymentEntityExt.setAddTime(now);
                paymentEntityExt.setUpdateTime(now);
                paymentEntityExt.setSysLong10(Objects.isNull(item.getSysLong10()) ? modelType : item.getSysLong10());
                serialTeamMap.put(item.getSerialNo(), item);
                formDataList.add(paymentEntityExt);
            });
            List<PaymentEntityExt> paymentEntityExtList = paymentModel.insertBatch(formDataList);
            insertList.addAll(paymentEntityExtList);
            paymentInsertBatchVO.setInsertList(insertList);
            paymentInsertBatchVO.setPaidForList(paidForList);
            //因为经销商应收款保存和普通应收款保存都会走这个方法
            //经销商或者开票产生应收或者出库产生应收
            boolean defaultUserInsertTag = Objects.equals(paymentInsertBatchDTO.getDistributorMark(),DistributorMarkEnum.DISTRIBUTOR.getCode())
                    || Objects.equals(ModelTypeEnum.INVOICE.getCode(), modelType) || Objects.equals(ModelTypeEnum.OUTSTOCK.getCode(), modelType);
            if (defaultUserInsertTag) {
                List<Long> paymentIdList = new ArrayList<>();
                JSONObject data =  paymentEntityExtList.get(0).getData();
                for (PaymentEntityExt paymentEntityExt : paymentEntityExtList){
                    paymentIdList.add(paymentEntityExt.getId());
                }
                Long customerId  = data.getLong(PaymentEnum.CUSTOMER.getAttr());
                Long contractId  = data.getLong(PaymentEnum.CONTRACT.getAttr());
                if (parentNew){
                    List<ReturnUserAndDepartmentPojo> ownerId = paymentInsertBatchDTO.getOwnerId() == null ? new ArrayList<>() : paymentInsertBatchDTO.getOwnerId();
                    List<ReturnUserAndDepartmentPojo> coUserId = paymentInsertBatchDTO.getCoUserId() == null ? new ArrayList<>() : paymentInsertBatchDTO.getCoUserId();
                    // 审批数据和导入数据没传userName,兼容一下
                    commonHelp.setUserName4UserPojo(corpid, ownerId, coUserId);
                    List<PaymentUserEntity> paymentUserEntityList = new ArrayList<>();
                    for (Long paymentId : paymentIdList) {
                        for (ReturnUserAndDepartmentPojo entity : ownerId) {
                            getPaymentUserTeam(customerId, contractId, paymentUserEntityList, paymentId, entity, BasicConstant.MAIN_USER, corpid);
                        }
                        for (ReturnUserAndDepartmentPojo entity : coUserId) {
                            getPaymentUserTeam(customerId, contractId, paymentUserEntityList, paymentId, entity, BasicConstant.COOP_USER, corpid);
                        }
                    }
                    if (!paymentUserEntityList.isEmpty()){
                        paymentUserModel.insertBatch(paymentUserEntityList);
                    }
                } else {
                    userTeamService.createPaymentUser(corpid,customerId,contractId,paymentIdList,PaymentLinkTypeEnum.CONTRACT.getCode(),false);
                }
            }else {
                //普通应收款走的方法
                teamDataHelp.savePayAndpaymentBatchBusUserTeam(paymentEntityExtList, serialTeamMap, paymentInsertBatchDTO.getLoginUser());
                try {
                    if (!Objects.equals(DistributorMarkEnum.DISTRIBUTOR.getCode(), paymentInsertBatchDTO.getDistributorMark())) {
                        PayDynamicStrategy payDynamicStrategy = dynamicStrategyFactory.getPayDynamicStrategyByBusinessType(paymentInsertBatchDTO.getBusinessType());
                        PaymentInsertBatchDTO dynamic = BeanUtil.copyProperties(paymentInsertBatchDTO, PaymentInsertBatchDTO.class, true);
                        transactionHelp.afterCommitOrCommitNow(p -> {
                            dynamic.setUserId(creatorId);
                            dynamic.setLoginUserName(null);
                            payDynamicStrategy.save(DynamicPayDTO.initSaveDynamicPayDTO(dynamic, paymentEntityExtList));
                        });
                    }
                } catch (Exception e) {
                    LOG.error("com.xbongbong.saas.service.impl.PaymentServiceImpl.insertBatch", e);
                }
            }
        } catch (Exception e) {
            LOG.error("paasFormData数据库保存表单数据出错", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        return paymentInsertBatchVO;
    }
    /**
     * 获取回款团队
     *
     * @param customerId
     * @param contractId
     * @param paymentUserEntityList
     * @param paymentId
     * @param entity
     * @param corpid
     */
    private void getPaymentUserTeam(Long customerId, Long contractId, List<PaymentUserEntity> paymentUserEntityList, Long paymentId, ReturnUserAndDepartmentPojo entity, Integer isMain, String corpid) {
        PaymentUserEntity paymentUserEntity = new PaymentUserEntity();
        paymentUserEntity.setCorpid(corpid);
        paymentUserEntity.setIsMain(isMain);
        paymentUserEntity.setUserId(entity.getId().toString());
        paymentUserEntity.setUserName(entity.getName());
        paymentUserEntity.setId(null);
        paymentUserEntity.setDataId(paymentId);
        paymentUserEntity.setCustomerId(customerId);
        paymentUserEntity.setContractId(contractId);
        paymentUserEntity.setRefType(PaymentLinkTypeEnum.CONTRACT.getCode());
        paymentUserEntityList.add(paymentUserEntity);
    }

    /**
     * 批量更新多个字段
     * @param paymentUpdateBatchMuchFieldDTO
     * @param source 用以标记日志的来源，true：回款计划普通编辑，false：回款计划批量编辑
     * @return
     * @throws XbbException
     */
    public PaymentUpdateBatchMuchFieldVO updateBatchMuchField(PaymentUpdateBatchMuchFieldDTO paymentUpdateBatchMuchFieldDTO, boolean source, Map<String, FieldAttrEntity> explainMap) throws XbbException {
        PaymentUpdateBatchMuchFieldVO paymentUpdateBatchMuchFieldVO = new PaymentUpdateBatchMuchFieldVO();
        // 批量更新流水号集合
        List<AddMuchFieldPojo> dataList = paymentUpdateBatchMuchFieldDTO.getDataList();
        List<String> updateBatchSerialNoList= new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        try {
            String corpid = paymentUpdateBatchMuchFieldDTO.getCorpid();
            Map<String, Object> map = BeanUtil.convertBean2Map(paymentUpdateBatchMuchFieldDTO, true);
            List<Long> idList = new ArrayList<>();

            List<PaymentEntityExt> updateList = new ArrayList<>();
            List<AddMuchFieldPojo> paidForList = new ArrayList<>();
            Map<Long,AddMuchFieldPojo> dataMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            HashMap<Long, Long> idTimeMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            dataList.forEach((item)->{
                idList.add(item.getId());
                JSONObject jsonObject = item.getData();
                String status = jsonObject.getString(PaymentEnum.STATUS.getAttr());
                if(PaymentStatusEnum.UN_RECEIVABLES.getCode().equals(status)) {
                    item.getData().put(PaymentEnum.UN_AMOUNT.getAttr(), item.getData().get(PaymentEnum.AMOUNT.getAttr()));
                }
                if(PaymentStatusEnum.RECEIVABLES.getCode().equals(status)) {
                    paidForList.add(item);
                }
                dataMap.put(item.getId(),item);
                idTimeMap.put(item.getId(), jsonObject.getLongValue(PaymentEnum.ESTIMATE_TIME.getAttr()));
//                jsonObjectList.add(ExplainUtil.getUpdateData(item.getId(), item.getData(), corpid));
            });
            map.put("idIn", idList);
            map.put("del", DelEnum.NORMAL.getDel());
            List<PaymentEntityExt> list = paymentModel.findEntitys(map);
            List<Long> esDeleteList = new ArrayList<>();
            Set<Long> idSet = new HashSet<>();
            //主要用于绑定应收款与团队的信息，只有编号是唯一值，所以编号-》团队
            Map<String, AddMuchFieldPojo> serialTeamMap = new HashMap<>();
            if (list == null) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_DATA_NOT_EXIST);
            } else {
                //状态code - 该状态禁止编辑的字段attrList
                Map<String, List<String>> unableEditAttrMap = PaymentBaseEnum.getUnableEditAttrMap();
                for(PaymentEntityExt paymentEntityExt: list) {
                    updateBatchSerialNoList.add(paymentEntityExt.getSerialNo());
                    JSONObject dbData = paymentEntityExt.getData();
                    AddMuchFieldPojo addMuchFieldPojo = dataMap.getOrDefault(paymentEntityExt.getId(),new AddMuchFieldPojo());
                    serialTeamMap.put(paymentEntityExt.getSerialNo(), addMuchFieldPojo);
                    String oldStatus = dbData.getString(PaymentEnum.STATUS.getAttr());
                    if (Objects.equals(dbData.getString(PaymentEnum.STATUS.getAttr()), addMuchFieldPojo.getData().getString(PaymentEnum.STATUS.getAttr()))) {
                        paidForList.removeIf(paid -> Objects.equals(paid.getId(), paymentEntityExt.getId()));
                    }
                    //该状态内不允许编辑的字段列表
                    List<String> paymentUnableEditAttrList = unableEditAttrMap.getOrDefault(oldStatus, new ArrayList<>());
                    for (Map.Entry<String,Object> entry : addMuchFieldPojo.getData().entrySet()){
                        //不允许编辑的字段里面没有这个字段
                        Boolean isEdit = !paymentUnableEditAttrList.contains(entry.getKey());
                        if ( isEdit ){
                            dbData.put(entry.getKey(),entry.getValue());
                        }
                    }
                    if (StringUtil.isNotEmpty(addMuchFieldPojo.getSerialNo())) {
                        paymentEntityExt.setSerialNo(addMuchFieldPojo.getSerialNo());
                    }
                    if (Objects.nonNull(addMuchFieldPojo.getDepartmentId())) {
                        paymentEntityExt.setDepartmentId(addMuchFieldPojo.getDepartmentId());
                    }
                    //需要更新应收账期
                    Long estimateTime = idTimeMap.get(paymentEntityExt.getId());
                    PeriodFilterPojo periodFilterPojo = fundSetService.getPeriodFilter4Payment(corpid, estimateTime, null, null, dbData.getLong(PaymentEnum.GENERATION_DATE.getAttr()));
                    JSONObject generationJson = new JSONObject();
                    generationJson.put(BasicConstant.TYPE, PeriodTypeEnum.DAY_AFTER.getCode());
                    generationJson.put(PeriodTypeEnum.DAY_AFTER.getAlias(),periodFilterPojo.getDay());
                    dbData.put(PaymentEnum.RECEIVABLE_PERIOD.getAttr(), generationJson.toJSONString());
                    fundHelp.removeNotInMapping(dbData);
                    paymentEntityExt.setData(dbData);
                    paymentEntityExt.setUpdateTime(DateUtil.getNow());
                    updateList.add(paymentEntityExt);
                    idSet.add(paymentEntityExt.getId());
                }
                for(Long id : idList) {
                    if (!idSet.contains(id)) {
                        esDeleteList.add(id);
                    }
                }
            }
            // 删除数据库没有，但是es有的数据
            if (!esDeleteList.isEmpty()) {
                paasEsModel.deleteBatch(esDeleteList, corpid, DelEnum.DELETE.getDel(), IndexTypeEnum.IDX_SAAS_PAYMENT);
            }
            paymentUpdateBatchMuchFieldVO.setPaidForList(paidForList);
            if (!updateList.isEmpty()) {
                paymentHelp.updateBatch(updateList, corpid, explainMap);
                if (!Objects.equals(paymentUpdateBatchMuchFieldDTO.getDistributorMark(), DistributorMarkEnum.DISTRIBUTOR.getCode())) {
                    //只有非经销商业务的应收款过来这边需要更新一下团队信息
                    teamDataHelp.savePayAndpaymentBatchBusUserTeam(updateList, serialTeamMap, paymentUpdateBatchMuchFieldDTO.getLoginUser());
                }
                //还需要更新tb_customer_statement表中对应的单据的更新时间
                BoolQueryBuilder boolQueryBuilder = chartQueryHelp.boolQueryBuilder4Base(corpid);
                boolQueryBuilder.filter(termQuery(CustomerStatementEnum.SYS_LONG_1.getAttr(), XbbRefTypeEnum.PAYMENT.getCode()));
                List<CustomerStatementEntity> result = formHelp.getFormListByIds4All(IndexTypeEnum.IDX_SAAS_CUSTOMER_STATEMENT,boolQueryBuilder, "sysLong2", idSet, null, CustomerStatementEntity.class);
                List<CustomerStatementEntity> finalResult = new ArrayList<>();
                //添加非空判断
                if (CollectionsUtil.isNotEmpty(result)){
                    for (CustomerStatementEntity customerStatementEntity : result) {
                        Long statementId = customerStatementEntity.getSysLong2();
                        //Long statementId = customerStatementEntity.getData().getLongValue(CustomerStatementEnum.STATEMENT_ID.getAttr());
                        if (idTimeMap.containsKey(statementId) && dataMap.containsKey(statementId)) {
                            //对账日期
                            Long checkingDate = customerStatementEntity.getData().getLong(CustomerStatementEnum.CHECKING_DATE.getAttr());
                            //应收金额  num_4
                            Double amountReceivable = customerStatementEntity.getData().getDouble(CustomerStatementEnum.AMOUNT_RECEIVABLE.getAttr());
                            //应收金额   num_1
                            Double paymentAmount = dataMap.get(statementId).getData().getDouble(PaymentEnum.AMOUNT.getAttr());
                            if (!Objects.equals(checkingDate, idTimeMap.get(statementId))
                                    || !Objects.equals(amountReceivable, paymentAmount)) {
                                customerStatementEntity.getData().put(CustomerStatementEnum.AMOUNT_RECEIVABLE.getAttr(), paymentAmount);
                                customerStatementEntity.getData().put(CustomerStatementEnum.CHECKING_DATE.getAttr(), idTimeMap.get(statementId));
                                customerStatementEntity.setUpdateTime(DateUtil.getNow());
                                finalResult.add(customerStatementEntity);
                            }
                        }
                    }
                }
                if (CollectionsUtil.isNotEmpty(finalResult)) {
                    customerStatementModel.updateBatch(finalResult, corpid);
                }
            }

            // 记录日志
            if(source){
                String updateBatchSerialNoStr = StringUtils.join(updateBatchSerialNoList, "，");
                String userId = paymentUpdateBatchMuchFieldDTO.getUserId();
                String loginUserName = paymentUpdateBatchMuchFieldDTO.getLoginUserName();
                if(dataList.size() > 1){
                    String memo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_BATCH_UPDATE_FORM_DETAIL), loginUserName, XbbRefTypeEnum.PAYMENT.getName(), dataList.size());
                    List<InfoArrPojo> infoArrPojoList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    InfoArrPojo infoArrPojo = new InfoArrPojo();
                    infoArrPojo.setTitle(PaymentEnum.PAYMENT_NO.getAttrName());
                    infoArrPojo.setContent(updateBatchSerialNoStr);
                    infoArrPojoList.add(infoArrPojo);
                    mongoLogHelp.buildLog4InfoArr(infoArrPojoList, corpid, userId, loginUserName, OperateModuleTypeEnum.PaymentManage, OperateTypeEnum.EDIT,
                            "", "", memo, paymentUpdateBatchMuchFieldDTO.getHttpHeader());
                } else if (Objects.equals(dataList.size(), 1)){
                    String memo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_UPDATE_WORK), loginUserName, XbbRefTypeEnum.PAYMENT.getName(), updateBatchSerialNoStr);
                    mongoLogHelp.buildLog(corpid, userId, loginUserName, OperateModuleTypeEnum.PaymentManage, OperateTypeEnum.EDIT,
                            dataList.get(0).getId().toString(), updateBatchSerialNoStr, memo, paymentUpdateBatchMuchFieldDTO.getHttpHeader());
                }
            }
        } catch (XbbException e) {
          throw e;
        } catch (Exception e) {
            LOG.error("paasFormData.updateBatchMuchField数据库批量更新出错", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        return paymentUpdateBatchMuchFieldVO;
    }

    @Override
    public PaymentDeleteBatchVO deleteBatch(PaymentDeleteBatchDTO paymentDeleteBatchDTO) throws XbbException {
        PaymentDeleteBatchVO paymentDeleteBatchVO = new PaymentDeleteBatchVO();
        String corpid = paymentDeleteBatchDTO.getCorpid();
        String userId = paymentDeleteBatchDTO.getUserId();
        String loginUserName = paymentDeleteBatchDTO.getLoginUserName();
        List<Long> idIn = paymentDeleteBatchDTO.getDataIdList();
        List<PaymentEntityExt> receivables = null;
        Map<Long,PaymentEntityExt> receivablesMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if ( idIn.size() > BasicConstant.MAX_DEL_BATCH_COUNT ) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100079.getCode(),SystemErrorCodeEnum.API_ERROR_100079.getMsg(), BasicConstant.MAX_DEL_BATCH_COUNT);
        }
        try {
            Iterator<Long> iterator = idIn.iterator();
            while (iterator.hasNext()) {
                if (Objects.isNull(iterator.next())) {
                    iterator.remove();
                }
            }
            List<PaasFormDataEntityExt> paymentList = new ArrayList<>();
            List<PaasFormDataEntityExt> deleteList = new ArrayList<>();
            if (!idIn.isEmpty()) {
                BoolQueryBuilder boolQueryBuilder = boolQuery();
                boolQueryBuilder.filter(termsQuery("dataId", idIn));
                boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
                if (Objects.nonNull(paymentDeleteBatchDTO.getStatus())) {
                    boolQueryBuilder.filter(termQuery("data."+ PaymentEnum.STATUS.getAttr(), paymentDeleteBatchDTO.getStatus()));
                }
                // List<String> fieldList = Arrays.asList(StringConstant.DATA_ID, StringConstant.FORM_ID, FieldTypeEnum.SERIALNO.getAlias(), "data." + PaymentEnum.RECEIVABLE_IS_RED.getAttr(),
                //         "data." + PaymentEnum.RED_AMOUNT.getAttr(), "data." + PaymentEnum.AMOUNT.getAttr(), "data." + PaymentEnum.RECEIVABLES_ORIGIN_ID.getAttr());
                deleteList = paymentList = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_PAYMENT, boolQueryBuilder, PaasFormDataEntityExt.class, Collections.emptyList());
                if (Objects.isNull(paymentList)) {
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
                }


                Set<Long> inApprovalIdList = new HashSet<>();
                Set<Long> inApprovalIdInvoiceList = new HashSet<>();

                if (commonHelp.isOpenWorkFlow(corpid)) {
                    // 开启工作流的时候从业务数据主表获取审批中数据
                    boolQueryBuilder = boolQuery();
                    boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
                    boolQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
                    boolQueryBuilder.filter(termsQuery(PaymentSheetEnum.getEsAttr4Keyword(PaymentSheetEnum.PAYMENT), idIn));
                    boolQueryBuilder.filter(termsQuery("flowStatus", Arrays.asList(FlowStatusEnum.APPROVAL_PENDING.getType(), FlowStatusEnum.IN_APPROVAL.getType())));
                    boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, IndexTypeEnum.IDX_SAAS_PAYMENT_SHEET.getType()));
                    List<PaasFormDataEntityExt> paymentSheetFormDataList = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_PAYMENT_SHEET,
                            boolQueryBuilder, PaasFormDataEntityExt.class, Arrays.asList(PaymentSheetEnum.getAttrConnectData(PaymentSheetEnum.PAYMENT), FieldTypeEnum.DATAID.getAlias()));

                    boolQueryBuilder = boolQuery();
                    boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
                    boolQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
                    boolQueryBuilder.filter(termsQuery(InvoiceEnum.getEsAttr4Keyword(InvoiceEnum.PAYMENT_ID), idIn));
                    boolQueryBuilder.filter(termsQuery("flowStatus", Arrays.asList(FlowStatusEnum.APPROVAL_PENDING.getType(), FlowStatusEnum.IN_APPROVAL.getType())));
                    boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, IndexTypeEnum.IDX_SAAS_INVOICE.getType()));
                    List<PaasFormDataEntityExt> invoiceFormDataList = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_INVOICE,
                            boolQueryBuilder, PaasFormDataEntityExt.class, Arrays.asList(InvoiceEnum.getAttrConnectData(InvoiceEnum.PAYMENT_ID), FieldTypeEnum.DATAID.getAlias()));

                    if (!paymentSheetFormDataList.isEmpty()) {
                        for (PaasFormDataEntityExt processDataEntity : paymentSheetFormDataList) {
                            JSONArray paymentArr = processDataEntity.getData().getJSONArray(PaymentSheetEnum.PAYMENT.getAttr());
                            paymentArr.forEach(item -> {
                                inApprovalIdList.add(Long.valueOf(item.toString()));
                            });
                        }
                    }
                    if (CollectionsUtil.isNotEmpty(invoiceFormDataList)) {
                        for (PaasFormDataEntityExt paasProcessDataEntity : invoiceFormDataList) {
                            JSONArray paymentArr = paasProcessDataEntity.getData().getJSONArray(InvoiceEnum.PAYMENT_ID.getAttr());
                            paymentArr.forEach(item -> {
                                inApprovalIdInvoiceList.add(Long.valueOf(item.toString()));
                            });
                        }
                    }
                } else {
                    // 在审批中的关联的回款单
                    List<PaasProcessDataEntity> processDataEntityList = paasProcessDataModel.getInApprovalDataByIdConditionJsonArray(XbbRefTypeEnum.PAYMENT_SHEET.getCode(), PaymentSheetEnum.PAYMENT.getAttr(), idIn, corpid, Arrays.asList(FlowStatusEnum.APPROVAL_PENDING.getType(), FlowStatusEnum.IN_APPROVAL.getType()));
                    List<PaasProcessDataEntity> processInvoiceDataEntityList = paasProcessDataModel.getInvoiceInApprovalDataByIdConditionJsonArray(XbbRefTypeEnum.INVOICE.getCode(), InvoiceEnum.PAYMENT_ID.getAttr(), idIn, corpid, Arrays.asList(FlowStatusEnum.APPROVAL_PENDING.getType(), FlowStatusEnum.IN_APPROVAL.getType()));
                    if (!processDataEntityList.isEmpty()) {
                        for (PaasProcessDataEntity processDataEntity : processDataEntityList) {
                            JSONArray paymentArr = JSONObject.parseObject(processDataEntity.getData()).getJSONArray(PaymentSheetEnum.PAYMENT.getAttr());
                            paymentArr.forEach(item -> {
                                inApprovalIdList.add(Long.valueOf(item.toString()));
                            });
                        }
                    }
                    if (CollectionsUtil.isNotEmpty(processInvoiceDataEntityList)) {
                        for (PaasProcessDataEntity paasProcessDataEntity : processInvoiceDataEntityList) {
                            JSONArray paymentArr = JSONObject.parseObject(paasProcessDataEntity.getData()).getJSONArray(InvoiceEnum.PAYMENT_ID.getAttr());
                            paymentArr.forEach(item -> {
                                inApprovalIdInvoiceList.add(Long.valueOf(item.toString()));
                            });
                        }
                    }
                }

                List<String> errorDataList = new ArrayList<>();
                List<String> errorTypeList = new ArrayList<>();
                for (PaasFormDataEntityExt paasFormDataEntityExt : paymentList) {
                    if (inApprovalIdList.contains(paasFormDataEntityExt.getDataId())) {
                        if(!errorTypeList.contains(PaymentErrorCodeEnum.API_ERROR_208008.getMsg())){
                            errorTypeList.add(PaymentErrorCodeEnum.API_ERROR_208008.getMsg());
                        }
                        errorDataList.add(paasFormDataEntityExt.getSerialNo());
                        idIn.remove(paasFormDataEntityExt.getDataId());
                    }
                }
                for(PaasFormDataEntityExt paasFormDataEntityExt : paymentList){
                    if(inApprovalIdInvoiceList.contains(paasFormDataEntityExt.getDataId())){
                        if(!errorTypeList.contains(InvoiceErrorCodeEnum.API_ERROR_216036.getMsg())){
                            errorTypeList.add(InvoiceErrorCodeEnum.API_ERROR_216036.getMsg());
                        }
                        errorDataList.add(paasFormDataEntityExt.getSerialNo());
                        idIn.remove(paasFormDataEntityExt.getDataId());
                    }
                }
                if ( !idIn.isEmpty() ){
                    List<Object> idInObjects = new ArrayList<>(idIn.size());
                    for (Long id:idIn ){
                        idInObjects.add(id);
                    }
                    Map<Long, PaasFormDataEntityExt> paymentSheetEntityExtMap = paymentSheetService.getEsDataMapByLinkIds(corpid, idInObjects, PaymentSheetEnum.PAYMENT);
                    List<Long> paymentSheetContractIds = new ArrayList<>();

                    //应收款红冲
                    Set<Long> receivablesSet = new HashSet<>();
                    List<Long> receivablesList = new ArrayList<>();
                    for (PaasFormDataEntityExt paasFormDataEntityExt : paymentList) {
                        PaasFormDataEntityExt paymentSheetEntityExt = paymentSheetEntityExtMap.get(paasFormDataEntityExt.getDataId());
                        if ( Objects.nonNull(paymentSheetEntityExt) ){
                            if(!errorTypeList.contains(PaymentErrorCodeEnum.API_ERROR_208038.getMsg())){
                                errorTypeList.add(PaymentErrorCodeEnum.API_ERROR_208038.getMsg());
                            }
                            errorDataList.add(paasFormDataEntityExt.getSerialNo());
                            paymentSheetContractIds.add(paasFormDataEntityExt.getDataId());
                        }
                        JSONObject paymentData = paasFormDataEntityExt.getData();
                        Integer receivablesIsRed = FastJsonHelper.getIntegerOrDefaultFromFormData(paymentData,PaymentEnum.RECEIVABLE_IS_RED.getAttr(),0);
                        if(Objects.equals(receivablesIsRed,BasicConstant.ONE)){
                            Long receivablesOriginId = FastJsonHelper.getLongOrDefaultFromFormData(paymentData,PaymentEnum.RECEIVABLES_ORIGIN_ID.getAttr(),0L);
                            receivablesSet.add(receivablesOriginId);
                        }
                    }
                    receivablesList.addAll(receivablesSet);
                    idIn.removeAll(paymentSheetContractIds);
                    //判断下面是否有发票
                    invoiceService.checkBusinessDeleteHaveInvoice(idIn,corpid,XbbRefTypeEnum.PAYMENT,errorTypeList,errorDataList,null,null,null,null,null,null,null);
                    if(CollectionsUtil.isNotEmpty(receivablesList) ) {
                        //删除红冲应收款
                        receivables = paymentModel.getPaymentByIdIn(corpid, receivablesList);
                        if(CollectionsUtil.isNotEmpty(receivables)) {
                            for (PaymentEntityExt paymentEntityExt : receivables) {
                                receivablesMap.put(paymentEntityExt.getId(),paymentEntityExt);
                                }
                        }
                    }
                }
                paymentDeleteBatchVO.setErrorDataList(errorDataList);
                if (!errorDataList.isEmpty()) {
                    paymentDeleteBatchVO.setErrorTypeList(errorTypeList);
                }
                paymentDeleteBatchVO.setErrorDataMemo(SaasDeleteHelp.getErrorDataMemo(errorTypeList, errorDataList));
            }
            //查询编号
            List<String> no= new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            List<UpdateDataEntity> updateDataEntityList = new ArrayList<>();
            Map<Long,Double> delRedReceivables = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            List<Long> delReceivables = new ArrayList<>();
            for(PaasFormDataEntityExt entityExt : paymentList){
                String sheetNo = entityExt.getSerialNo();
                no.add(sheetNo);
                JSONObject data = entityExt.getData();
                Integer isRedReceivable = FastJsonHelper.getIntegerOrDefaultFromFormData(data,PaymentEnum.RECEIVABLE_IS_RED.getAttr(),0);
                Long receivablesOriginId = FastJsonHelper.getLongOrDefaultFromFormData(data,PaymentEnum.RECEIVABLES_ORIGIN_ID.getAttr(),0L);
                if(Objects.equals(isRedReceivable,BasicConstant.ONE)) {
                    PaymentEntityExt paymentEntityExt = receivablesMap.get(receivablesOriginId);
                    Double redAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(data, PaymentEnum.AMOUNT.getAttr(), 0D);
                    //删除的红冲应收款金额
                    if (Objects.nonNull(paymentEntityExt)) {
                        saasSaveHelp.addMapNormal(delRedReceivables,paymentEntityExt.getId(),redAmount);
                    }
                }else {
                    delReceivables.add(entityExt.getDataId());
                }
            }
            Iterator<Map.Entry<Long,PaymentEntityExt>> it = receivablesMap.entrySet().iterator();
            while (it.hasNext()){
                //删除红冲应收款的时候需要增加原应收款未收，以及减少原红冲应收
                Map.Entry<Long,PaymentEntityExt> entry = it.next();
                PaymentEntityExt paymentEntityExt = entry.getValue();
                JSONObject data = paymentEntityExt.getData();
                Double originRedAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(data, PaymentEnum.RED_AMOUNT.getAttr(), 0D);
                //红冲应收款中的红冲金额
                Double redRedAmount = delRedReceivables.getOrDefault(paymentEntityExt.getId(),0D);
                Double sumRedReceivables = Arith.sub(originRedAmount,redRedAmount);
                data.put(PaymentEnum.RED_AMOUNT.getAttr(),sumRedReceivables);
                //原应收的未收金额
                Double originUnAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(data, PaymentEnum.UN_AMOUNT.getAttr(), 0D);
                Double fininalUnAmount = Arith.sub(originUnAmount,redRedAmount);
                data.put(PaymentEnum.UN_AMOUNT.getAttr(), fininalUnAmount);
                //原应收款的状态
                Double planAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(data, PaymentEnum.AMOUNT.getAttr(), 0D);
                String status = handleStatus(planAmount, fininalUnAmount, 0D, sumRedReceivables);
                data.put(PaymentEnum.STATUS.getAttr(), status);
                //解决bug: 38511
                Long contractId = data.getLong(PaymentEnum.CONTRACT.getAttr());
                ContractEntityExt contractEntityExt = contractModel.getByKey(contractId, corpid);
                Double contractAmount = contractEntityExt.getData().getDoubleValue(ContractEnum.AMOUNT.getAttr());
                BoolQueryBuilder paymentSumBoolQueryBuilder = boolQuery();
                paymentSumBoolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
                paymentSumBoolQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
                paymentSumBoolQueryBuilder.filter(termQuery(PaymentEnum.getEsAttr4Keyword(PaymentEnum.CONTRACT), contractId));
                JSONObject paymentHasExistAmountJson= esHelper.sumMuchField4Some(IndexTypeEnum.IDX_SAAS_PAYMENT, paymentSumBoolQueryBuilder, Arrays.asList(PaymentEnum.getEsAttr4Keyword(PaymentEnum.AMOUNT)));
                Double paymentHasExistAmount = paymentHasExistAmountJson.getDoubleValue(PaymentEnum.getEsAttr4Keyword(PaymentEnum.AMOUNT));
                if (Arith.sub(contractAmount, Arith.sub(paymentHasExistAmount, redRedAmount)) < BasicConstant.ZERO_DOUBLE) {
                    idIn.clear();
                    throw new XbbException(PaymentErrorCodeEnum.API_ERROR_208080);
                }
                UpdateDataEntity updateDataEntity = ExplainUtil.getUpdateData(paymentEntityExt.getId(), data, corpid);
                updateDataEntityList.add(updateDataEntity);

            }
            //删除应收款，分两种情况：如果删除是红冲应收款，需要更新原始应收款已收、未收信息；如果删除是普通应收款，需要删除普通应收款以及应收款下的红冲应收款。
            if (!idIn.isEmpty()) {
                //根据应收款id去查询红冲应收款id列表
                if (CollectionsUtil.isNotEmpty(delReceivables)) {
                    BoolQueryBuilder boolQueryBuilder = boolQuery();
                    boolQueryBuilder.filter(termsQuery(PaymentEnum.getEsAttr4Keyword(PaymentEnum.RECEIVABLES_ORIGIN_ID), delReceivables));
                    boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
                    List<String> fieldList = Arrays.asList(StringConstant.DATA_ID);
                    paymentList = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_PAYMENT, boolQueryBuilder, PaasFormDataEntityExt.class, fieldList);
                    if (CollectionsUtil.isNotEmpty(paymentList)) {
                        paymentList.forEach(payment -> idIn.add(payment.getDataId()));
                    }
                }
                if(BasicConstant.ONE.equals(paymentDeleteBatchDTO.getSingleFlag())
                        && BasicConstant.ONE.equals(idIn.size())){
                    paymentModel.deleteByKey(idIn.get(0),corpid);
                }else {
                    paymentModel.deleteBatch(idIn, paymentDeleteBatchDTO.getCorpid(), DelEnum.DELETE.getDel());
                }
                if (CollectionsUtil.isNotEmpty(updateDataEntityList)) {
                    paymentModel.updateBatch(updateDataEntityList,corpid);
                }
                //删除对应应收款的团队
                if (CollectionsUtil.isNotEmpty(idIn)) {
                    List<UserTeamEntity> userTeamEntities = userTeamHelp.getUserTeamList(idIn, corpid, XbbRefTypeEnum.PAYMENT.getCode(), false, null);
                    if (CollectionsUtil.isNotEmpty(userTeamEntities)) {
                        List<Long> userIdIn = userTeamEntities.stream().map(UserTeamEntity::getId).collect(Collectors.toList());
                        paymentUserModel.batchUpdateByUserIdIn(corpid, userIdIn, userTeamEntities, null, BasicConstant.ONE);
                    }
                }

                try {
                    if (!Objects.equals(DistributorMarkEnum.DISTRIBUTOR.getCode(), paymentDeleteBatchDTO.getDistributorMark())) {
                        DynamicStrategy dynamicStrategy = dynamicStrategyFactory.getDynamicStrategyByBusinessType(paymentDeleteBatchDTO.getBusinessType());
                        FormDataDeleteBatchDTO formDataDeleteBatchDTO  = BeanUtil.copyProperties(paymentDeleteBatchDTO, FormDataDeleteBatchDTO.class, true);
                        List<PaasFormDataEntityExt> finalDeleteList = deleteList;
                        transactionHelp.afterCommitOrCommitNow(p -> {
                            dynamicStrategy.batchDelete(DynamicDeleteDTO.initDynamicDeleteDTO(formDataDeleteBatchDTO, idIn, finalDeleteList.stream().filter(item -> idIn.contains(item.getDataId())).collect(Collectors.toList())));
                        });
                    }
                } catch (Exception e) {
                    LOG.error("删除应收款动态失败：", e);
                }

                //删除应收的时候需要同时删除对账单,根据应收款id查询出对应的对账单id
                customerStatementService.deleteBatch(corpid, XbbRefTypeEnum.PAYMENT.getCode(), idIn);
//                // 回款单删除不影响列表回显
//                Runnable runnable = () -> {
//                    try {
//                        paymentSheetService.deleteBatch(idIn,corpid,userId,loginUserName);
//                    } catch (XbbException e) {
//                        LOG.error("删除回款计划时,同步删除回款单", e);
//                    }
//                };
//                threadPoolBeanConfig.addUpdateDelThreadPool().execute(runnable);

                //
            }
            OperateTypeEnum operateTypeEnum = OperateTypeEnum.DELETE;
            if (Objects.equals(1, paymentDeleteBatchDTO.getIsBusinessRule())) {
                operateTypeEnum = OperateTypeEnum.RULE_DELETE;
            }
            //生成删除日志(区分单个删除和批量删除)
            // 合同覆盖导入时会触发删除操作，这里暂时过滤这个日志处理
            if(!Objects.equals(1, paymentDeleteBatchDTO.getIsImport())){
                List<String> errorData = paymentDeleteBatchVO.getErrorDataList();
                //取差集
                errorData.forEach(e -> no.removeIf(str -> Objects.equals(str, e)));
                String nameStr = StringUtils.join(no, "，");
                if(idIn.size() > 1){
                    String memo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_BATCH_DELETE_FORM_DETAIL), loginUserName, XbbRefTypeEnum.PAYMENT.getName(), idIn.size());
                    List<InfoArrPojo> infoArrPojoList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    InfoArrPojo infoArrPojo = new InfoArrPojo();
                    infoArrPojo.setTitle(PaymentEnum.PAYMENT_NO.getAttrName());
                    infoArrPojo.setContent(nameStr);
                    infoArrPojoList.add(infoArrPojo);
                    mongoLogHelp.buildLog4InfoArr(infoArrPojoList, corpid, userId, loginUserName, OperateModuleTypeEnum.PaymentManage, operateTypeEnum,
                            "", "", memo, paymentDeleteBatchDTO.getHttpHeader());
                } else if (Objects.equals(idIn.size(), 1)){
                    String memo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_DELETE_WORK), loginUserName, XbbRefTypeEnum.PAYMENT.getName(), nameStr);
                    mongoLogHelp.buildLog(corpid, userId, loginUserName, OperateModuleTypeEnum.PaymentManage, operateTypeEnum,
                            idIn.get(0).toString(), nameStr, memo, paymentDeleteBatchDTO.getHttpHeader());
                }
            }
            paymentDeleteBatchVO.setDeleteIds(idIn);
            paymentDeleteBatchVO.setPaymentList(paymentList);
        } catch (XbbException e){
            updateRollback(paymentDeleteBatchDTO.getDataIdList(), corpid);
            throw e;
        }catch (Exception e) {
            updateRollback(paymentDeleteBatchDTO.getDataIdList(), corpid);
            LOG.error("paymentService.delteBatch批量删除出错", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        return paymentDeleteBatchVO;
    }

    @Override
    public void validatePayment(PaymentDTO payMentDTO) throws XbbException {
        try {
            List<AddMuchFieldPojo> addBatchList = payMentDTO.getAddBatchList();
            List<AddMuchFieldPojo> updateBatchList = payMentDTO.getUpdateBatchList();
            List<AddMuchFieldPojo> delBatchList = payMentDTO.getDelBatchList();
            // 需要插入的数据或需要更新数据不为空
            Long amount = 0L;
            Long contractId = 0L;
            List<String> serialNoList = new ArrayList<>();
            if(Objects.nonNull(addBatchList) && !addBatchList.isEmpty()) {
                for (AddMuchFieldPojo item : addBatchList) {
                    String serialNo = item.getSerialNo();
                    if (StringUtil.isNotEmpty(serialNo)) {
                        serialNoList.add(serialNo);
                    }
                    amount += item.getData().getLong(PaymentEnum.AMOUNT.getAttr());
                    JSONObject data = item.getData();
                    amount += data.getLong(PaymentEnum.AMOUNT.getAttr());
                    contractId = data.getLong(PaymentEnum.CONTRACT.getAttr());
                }
            }
            Map<String, Long> serialNoMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            if(Objects.nonNull(updateBatchList) && !updateBatchList.isEmpty()){
                for (AddMuchFieldPojo item : updateBatchList) {
                    String serialNo = item.getSerialNo();
                    if (StringUtil.isNotEmpty(serialNo)) {
                        serialNoList.add(serialNo);
                        serialNoMap.put(serialNo, item.getId());
                    }
                    JSONObject data = item.getData();
                    amount += data.getLong(PaymentEnum.AMOUNT.getAttr());
                    contractId = data.getLong(PaymentEnum.CONTRACT.getAttr());
                }
            }
            Long subtractedAmount = 0L;
            if(Objects.nonNull(delBatchList) && !delBatchList.isEmpty()){
                for (AddMuchFieldPojo item : delBatchList) {
                    JSONObject data = item.getData();
                    subtractedAmount += data.getLong(PaymentEnum.AMOUNT.getAttr());
                    contractId = data.getLong(PaymentEnum.CONTRACT.getAttr());
                }
            }
            // 获取新建的和更新计划收款金额总和减去删除的计划收款金额
            Long resultAmount = amount - subtractedAmount;
            ContractEntityExt contractEntityExt = contractModel.getByKey(contractId, payMentDTO.getCorpid());
            if(Objects.isNull(contractEntityExt)){
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.CONTRACT_NOT_EXISTS);
            }
            JSONObject contractData = contractEntityExt.getData();
            Long contractAmount = contractData.getLong(ContractEnum.AMOUNT.getAttr());
            // 新建的和更新计划收款金额总和减去删除的计划收款金额不能大于合同金额
            //允许误差小于等于ConfigConstant.amountAccuracy
            if (Arith.sub(resultAmount, contractAmount) > ConfigConstant.amountAccuracy) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.PAYMENT_NOT_MORE_THAN_CONTRACT);
            }
            if (!serialNoList.isEmpty()) {
                Set<String> serialSet = new HashSet<>();
                for (String serialNo : serialNoList) {
                    serialSet.add(serialNo);
                }
                if(serialNoList.size() != serialSet.size()) {
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.SAME_DATA_EXISTS);
                }
                FormDataRepeatBatchDTO formDataRepeatBatchDTO = new FormDataRepeatBatchDTO();
                BeanUtil.copyProperties(payMentDTO, formDataRepeatBatchDTO);
                formDataRepeatBatchDTO.setSerialNoList(serialNoList);
                FormDataRepeatBatchVO formDataRepeatBatchVO = paasFormDataService.repeatBatch(formDataRepeatBatchDTO);
                if(Objects.isNull(formDataRepeatBatchVO)) {
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
                }
                List<PaasFormDataEntityExt> formDataList = formDataRepeatBatchVO.getFormDataList();
                if(Objects.isNull(formDataList)){
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
                }
                if(!formDataList.isEmpty() && formDataList.size() > 1){
                    for (PaasFormDataEntityExt item : formDataList) {
                        // 根据编号获取数据id，如果id和数据库存储不一致，则为重复数据
                        if (!serialNoMap.isEmpty() && !serialNoMap.get(item.getSerialNo()).equals(item.getDataId())) {
                            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.DUPLICATE_VALUE, "");
                        }
                    }
                }
            }

        } catch (XbbException e) {
            throw e;
        } catch (Exception e) {
            LOG.error("paymentServiceImpl.repeatBatch判重出错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
    }

    @Override
    public PaymentUpdateByBusinessRuleVO updateFormDataByBusinessRule(PaymentUpdateByBusinessRuleDTO paymentUpdateByBusinessRuleDTO) throws XbbException {
        PaymentUpdateByBusinessRuleVO paymentUpdateByBusinessRuleVO = new PaymentUpdateByBusinessRuleVO();
        try {
            String corpid = paymentUpdateByBusinessRuleDTO.getCorpid();
            List<PaasFormDataEntityExt> formDataList = paymentUpdateByBusinessRuleDTO.getFormDataList();
            List<UpdateDataEntity> updateList = ExplainUtil.getUpdateValueByBusinessRule(formDataList, corpid, paymentUpdateByBusinessRuleDTO.getOperations());

            if (!updateList.isEmpty()) {
                paymentModel.updateBatch(updateList, corpid);
                RuleBusinessLogDTO businessLogDTO = new RuleBusinessLogDTO();
                BeanUtil.copyProperties(paymentUpdateByBusinessRuleDTO, businessLogDTO);
                businessLogDTO.setFormDataList(formDataList);
                ruleBusinessLogger.writeLog(businessLogDTO, updateList);
            }
        } catch (Exception e) {
            LOG.error("paymentServiceImpl.updateFormDataByBusinessRule根据业务规则更新数据出错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        return paymentUpdateByBusinessRuleVO;
    }

    /**
     * 判断回款的回款单是否有在审批中
     *
     * @param paymentId 应收款id
     * @param corpid    公司id
     * @return 创建时间： 2017-12-14 下午9:32:20
     * 修改时间：
     * @author chy
     */
    @Override
    public boolean paymentApproval(Long paymentId, String corpid) {
        List<PaasProcessDataEntity> sheetInApproval = paasProcessDataModel.getInApprovalDataByIdCondition(XbbRefTypeEnum.PAYMENT_SHEET.getCode(), PaymentSheetEnum.PAYMENT.getAttr(), Collections.singletonList(paymentId), corpid, Arrays.asList(FlowStatusEnum.APPROVAL_PENDING.getType(),FlowStatusEnum.IN_APPROVAL.getType()));
        return !sheetInApproval.isEmpty();
    }
    @Override
    public ListAppVO formatPaymentAppList(FormDataListDTO formDataListDTO, List<PaasFormDataEntityExt> esEntities, Integer totalCount) throws XbbException {
        List<AppListPojo> appListPojos = new ArrayList<>();
        for (PaasFormDataEntityExt paymentEntity : esEntities) {
            JSONObject data = paymentEntity.getData();
            Long paymentId = paymentEntity.getId();
            Long appId = paymentEntity.getAppId();
            Long menuId = paymentEntity.getMenuId();
            Long formId = paymentEntity.getFormId();
            JSONObject superScript = new JSONObject();
            JSONObject others = new JSONObject();

            //由于回款状态是下拉框类型的字段，上面被渲染成了ItemPojo类型，转一下
            String status = commonHelp.formatFundStatusText(data, PaymentEnum.PAYMENT_TYPE.getAttr(),"");
            /*-- 其他 -*/
            String amount =FastJsonHelper.getStringOrDefaultFromFormData(data, PaymentEnum.AMOUNT.getAttr(), "0.0");
            Integer isRed = FastJsonHelper.getIntegerOrDefaultFromFormData(data, PaymentEnum.RECEIVABLE_IS_RED.getAttr(), 0);
            Integer isBad = 0;
            if ( Objects.equals(PaymentStatusEnum.getByAlias(status),PaymentStatusEnum.BAD_DEBT)
                    || Objects.equals(PaymentStatusEnum.getByAlias(status),PaymentStatusEnum.PARTIAL_BAD_DEBT)){
                isBad = 1;
            }
            String realAmount = FastJsonHelper.getStringOrDefaultFromFormData(data, REAL_AMOUNT.getAttr(), "0.0");
            /*if (Objects.equals(isRed, BasicConstant.ONE)) {
                // 如果包含负数，则金额为负，那么代表这个红冲回款，那么就展示红冲金额
                amount = realAmount;
            }*/
            amount = amount + UnitEnum.MONEY.getName();
            commonHelp.setPaymentOthers(others, amount, status, isRed,isBad);

            List<SummaryDataPoJo> summaryList = FastJsonHelper.getJsonArrOrDefaultFromFormData(data, BasicConstant.SUMMARY_LIST, new JSONArray()).toJavaList(SummaryDataPoJo.class);
            List<SummaryDataPoJo> lablesList = FastJsonHelper.getJsonArrOrDefaultFromFormData(data, BasicConstant.LABELS_LIST, new JSONArray()).toJavaList(SummaryDataPoJo.class);
            List<FormTitlePoJo> titleList = FastJsonHelper.getJsonArrOrDefaultFromFormData(data, BasicConstant.TITLE_LIST, new JSONArray()).toJavaList(FormTitlePoJo.class);
            //@author chenshan
            if ( Objects.equals(status, PaymentStatusEnum.UN_RECEIVABLES.getAlias()) || Objects.equals(status, PaymentStatusEnum.PARTIAL_RECEIPTS.getAlias()) ) {
                for ( SummaryDataPoJo summaryDataPoJo : summaryList ) {
                    String attr = summaryDataPoJo.getAttr();
                    if ( Objects.equals(attr, PaymentEnum.ESTIMATE_TIME.getAttr()) ) {
                        List<Object> valueList = summaryDataPoJo.getValue();
                        if ( valueList.isEmpty() ) {
                            break;
                        }
                        String valueKey = (String) valueList.get(0);
                        Long estimate = DateTimeUtil.getInt(valueKey, DateTimeUtil.SDFDate);
                        if ( estimate < DateTimeUtil.getTodayInt() ) {
                            summaryDataPoJo.setStatus("delay");
                        }
                        break;
                    }
                }

                Long estimateTime = FastJsonHelper.getLongOrDefaultFromFormData(data,PaymentEnum.ESTIMATE_TIME.getAttr(),0L);
                Double unAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(data,PaymentEnum.UN_AMOUNT.getAttr(),0D);
                if(Objects.nonNull(estimateTime) && estimateTime < DateUtil.getTodayInt() && unAmount > 0){
                    JSONObject detail = new JSONObject();
                    detail.put("memo",TagEnum.TAG_OVERDUE.getMemo());
                    superScript.put(TagEnum.TAG_OVERDUE.getAttr(),detail);
                }
            }
            //app系统关联数据展示需要 others 和 superScript; 因为上面对summaryList 中的 setStatus 进行了设置，所以需要覆盖掉 data原来的summaryList
            data.put("others",others);
            data.put("superScript",superScript);
            data.put("summaryList",summaryList);

            appListPojos.add(new AppListPojo(paymentId, titleList, summaryList, superScript, lablesList, others, appId, menuId, formId));
        }
        ListAppVO listAppVO = new ListAppVO();
        listAppVO.setList(appListPojos);
        listAppVO.setTotalCount(totalCount);
        return  listAppVO;
    }

    @Override
    public void formatLinkAddExplain(HandlerExplainInLinkItemDTO handlerExplainInLinkItemDTO) throws XbbException {
        JSONObject linkFormData = handlerExplainInLinkItemDTO.getLinkFormData();
        Long linkDataId = handlerExplainInLinkItemDTO.getLinkDataId();
        List<FieldAttrEntity> explainList = handlerExplainInLinkItemDTO.getExplainList();
        PaasFormDataEntityExt paasFormDataEntityExt = handlerExplainInLinkItemDTO.getPaasFormDataEntityExt();
        FieldAttrEntity linkCustomerField = new FieldAttrEntity();
        FieldAttrEntity linkContractField = new FieldAttrEntity();
        FieldAttrEntity linkReceivablesOriginIdField = new FieldAttrEntity();
        FieldAttrEntity linkSourceTypeField = new FieldAttrEntity();
        FieldAttrEntity linkSourceField = new FieldAttrEntity();
        for(FieldAttrEntity fieldAttrEntity :explainList) {
            if (Objects.equals(fieldAttrEntity.getAttr(), PaymentEnum.CUSTOMER.getAttr())) {
                linkCustomerField = fieldAttrEntity;
            } else if (Objects.equals(fieldAttrEntity.getAttr(), PaymentEnum.CONTRACT.getAttr())) {
                linkContractField = fieldAttrEntity;
            } else if(Objects.equals(fieldAttrEntity.getAttr(),PaymentEnum.RECEIVABLES_ORIGIN_ID.getAttr())){
                linkReceivablesOriginIdField = fieldAttrEntity;
            } else if(Objects.equals(fieldAttrEntity.getAttr(),PaymentEnum.SOURCE_REF_TYPE.getAttr())){
                linkSourceTypeField = fieldAttrEntity;
            } else if(Objects.equals(fieldAttrEntity.getAttr(),PaymentEnum.SOURCE.getAttr())){
                linkSourceField = fieldAttrEntity;
            } else if(Objects.equals(fieldAttrEntity.getAttr(),PaymentEnum.AMOUNT.getAttr())){
                Double unAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(linkFormData,PaymentEnum.UN_AMOUNT.getAttr(),0D);
                fieldAttrEntity.setDefaultAttr(saasUpdateHelp.setDefaultValue(unAmount));
            }
        }
        RedundantTemplateTypeEnum redundantTemplateTypeEnum = RedundantTemplateTypeEnum.getByCode(handlerExplainInLinkItemDTO.getLinkBusinessType());
        String customerName = "";
        switch (redundantTemplateTypeEnum) {
            case CUSTOMER:
                //TODO 应收款无用代码
                customerName = FastJsonHelper.getStringOrDefaultFromFormData(linkFormData, CustomerManagementEnum.NAME.getAttr(), "");
                linkCustomerField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(linkDataId, customerName));
                break;
            case CONTRACT:
                //TODO 应收款无用代码
                String contractNo = paasFormDataEntityExt.getSerialNo();
                DefaultAttrPoJo defaultAttrPoJo = saasUpdateHelp.getDefaultAttrPojo(linkDataId, contractNo);

                String totalMoney = linkFormData.getString(ContractEnum.AMOUNT.getAttr());
                Object linkFormValueObject = defaultAttrPoJo.getLinkFormValue();

                FormDataUpdateGetDTO formDataUpdateGetDTO = new FormDataUpdateGetDTO();
                BeanUtil.copyProperties(handlerExplainInLinkItemDTO,formDataUpdateGetDTO);
                formDataUpdateGetDTO.setDataId(handlerExplainInLinkItemDTO.getLinkDataId());
                //合同金额=(预收款核销金额+回款单核销金额)+回款计划金额-回款计划已收金额-回款计划已坏金额+(坏账金额+已红冲金额-重复的红冲账金额)
                Double finishAmount = fundMoneyHelp.getWriteOffAmount(formDataUpdateGetDTO,XbbRefTypeEnum.CONTRACT.getCode());
                if (linkFormValueObject instanceof JSONArray) {
                    JSONArray linkFormValueArray = (JSONArray)linkFormValueObject;
                    for (Object linkFormValue : linkFormValueArray) {
                        JSONObject linkFormValueJson = (JSONObject)linkFormValue;
                        linkFormValueJson.put(ContractEnum.AMOUNT.getAttr(), totalMoney);
                        linkFormValueJson.put(StringConstant.FINISH_AMOUNT, finishAmount);
                    }
                }
                linkContractField.setDefaultAttr(defaultAttrPoJo);

                JSONArray linkCustomerArr = FastJsonHelper.getJsonArrOrDefaultFromFormData(linkFormData, ContractEnum.LINK_CUSTOMER.getAttr(), new JSONArray());
                linkCustomerField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(linkCustomerArr));
                break;
            case PAYMENT:
                JSONArray customerArray = FastJsonHelper.getJsonArrOrDefaultFromFormData(linkFormData,PaymentEnum.CUSTOMER.getAttr(),new JSONArray());
                if(customerArray.size() > BasicConstant.ZERO) {
                    Long customerId = FastJsonHelper.getLongOrDefaultFromFormData(customerArray.getJSONObject(BasicConstant.ZERO), BasicConstant.ID, 0L);
                    customerName = FastJsonHelper.getStringOrDefaultFromFormData(customerArray.getJSONObject(BasicConstant.ZERO), BasicConstant.NAME, "");
                    linkCustomerField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(customerId, customerName));
                }
                JSONArray contractArray = FastJsonHelper.getJsonArrOrDefaultFromFormData(linkFormData,PaymentEnum.CONTRACT.getAttr(),new JSONArray());
                if(contractArray.size() > BasicConstant.ZERO) {
                    Long contractId = FastJsonHelper.getLongOrDefaultFromFormData(contractArray.getJSONObject(BasicConstant.ZERO), BasicConstant.ID, 0L);
                    String contractName = FastJsonHelper.getStringOrDefaultFromFormData(contractArray.getJSONObject(BasicConstant.ZERO), BasicConstant.NAME, "");
                    linkContractField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(contractId, contractName));
                }
                Long originId = paasFormDataEntityExt.getId();
                String originName = paasFormDataEntityExt.getSerialNo();
                linkReceivablesOriginIdField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(originId, originName));
                Integer sourceBusinessType = FastJsonHelper.getIntegerOrDefaultFromFormData(linkFormData,PaymentEnum.SOURCE_REF_TYPE.getAttr(),0);
                linkSourceTypeField.setDefaultAttr(saasUpdateHelp.setDefaultValue(sourceBusinessType));
                JSONArray sourceArray = FastJsonHelper.getJsonArrOrDefaultFromFormData(linkFormData,PaymentEnum.SOURCE.getAttr(),new JSONArray());
                if(sourceArray.size() > BasicConstant.ZERO){
                    Long sourceId = FastJsonHelper.getLongOrDefaultFromFormData(sourceArray.getJSONObject(BasicConstant.ZERO), BasicConstant.ID, 0L);
                    String sourceName = FastJsonHelper.getStringOrDefaultFromFormData(sourceArray.getJSONObject(BasicConstant.ZERO), BasicConstant.NAME, "");
                    linkSourceField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(sourceId, sourceName));
                }
                break;
            default:
                throw new XbbException(TemplateErrorCodeEnum.API_ERROR_350006);
        }
    }

    /**
     * 资金管理应收款关联红冲回款单
     *
     * @param corpid    用户信息
     * @param paymentId 应收款id
     * @return 红冲应收款
     */
    @Override
    public List<PaasFormDataEntityExt> getAssociationRedSheetList(String corpid, Long paymentId) throws XbbException{
        List<PaasFormDataEntityExt> paasFormDataESList = new ArrayList<>();
        Map<String,Object> modelMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        modelMap.put(ParameterConstant.CORPID, corpid);
        modelMap.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
        List<PaasFormDataEntityExt> paasFormDataEntityExts = paasEsModel.selectByOneCondition(XbbRefTypeEnum.PAYMENT.getCode(), PaymentEnum.ORIGIN_ID.getAttr(), paymentId.toString(), modelMap, IndexTypeEnum.IDX_SAAS_PAYMENT);
        List<Object> redPaymentIdIn = new ArrayList<>();
        paasFormDataEntityExts.forEach(paasFormDataEntityExt -> redPaymentIdIn.add(paasFormDataEntityExt.getId()));
        if (!redPaymentIdIn.isEmpty()) {
            List<ConditionsEntityExt > conditions = new ArrayList<>();
            conditions.add(EsUtil.packageContions(PaymentSheetEnum.PAYMENT.getAttr(), redPaymentIdIn, ConditionEnum.IN, FieldTypeEnum.TEXT.getType()));
            conditions.add(EsUtil.packageContions(PaymentSheetEnum.PAYMENT_SHEET_TYPE.getAttr(), Collections.singletonList(PaymentSheetTypeEnum.RED_WRITE_OFF.getCode()), ConditionEnum.EQUAL, FieldTypeEnum.NUM.getType()));
            PaasFormDataEsListVO paasFormDataEsListVO = saasDetailTabService.getEsListOnlyByCondition(corpid, XbbRefTypeEnum.PAYMENT_SHEET.getCode(), conditions);
            paasFormDataESList = paasFormDataEsListVO.getPaasFormDataESList();
        }
        return paasFormDataESList;
    }


    @Override
    public void batchEditAttr(PaymentEditAttrUpdateDTO paymentEditAttrUpdateDTO) throws XbbException {
        try {
            String corpid = paymentEditAttrUpdateDTO.getCorpid();
            Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            param.put("corpid", corpid);
            param.put("idIn", paymentEditAttrUpdateDTO.getDataIdList());
            List<PaymentEntityExt> paymentEntityList  = paymentModel.findEntitys(param);
            if (Objects.isNull(paymentEntityList)){
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
            }
            //权限团队校验前置了
            List<Long> errorIdList = new ArrayList<>();
//            List<Long> errorIdList = userTeamHelp.batchTeamMembersCheckEditPermission(paymentEditAttrUpdateDTO.getBusinessType(), paymentEditAttrUpdateDTO.getSaasMark(),
//                    paymentEditAttrUpdateDTO.getMenuId(), paymentEditAttrUpdateDTO.getLoginUser(), paymentEditAttrUpdateDTO.getDistributorMark(),
//                    paymentEditAttrUpdateDTO.getDataIdList(), new HashMap<>());
            List<String> errorNameList = new ArrayList<>();
            for (PaymentEntityExt paymentEntityExt : paymentEntityList) {
                if (errorIdList.contains(paymentEntityExt.getId())) {
                    errorNameList.add(paymentEntityExt.getSerialNo());
                }
            }
            String nameStr = org.apache.commons.lang.StringUtils.join(errorNameList, "、");
            if (CollectionUtils.isNotEmpty(errorNameList)) {
                throw new XbbException(UserTeamErrorCodeEnum.API_ERROR_271038.getCode(), String.format(UserTeamErrorCodeEnum.API_ERROR_271038.getMsg(), nameStr));
            }
            List<PaymentUpdateDTO> paymentUpdateList =new ArrayList<>();
            paymentEditAttrUpdateDTO.getDataIdList().forEach((item)->{
                PaymentUpdateDTO payment = new PaymentUpdateDTO();
                payment.setId(item);
                JSONObject data = ProSaveHelp.getBatchUpdateData(paymentEditAttrUpdateDTO.getFieldEditedList());
                payment.setData(data);
                paymentUpdateList.add(payment);
            });
            if (!paymentUpdateList.isEmpty()) {
                PaymentUpdateBatchDTO paymentUpdateBatchDTO = new PaymentUpdateBatchDTO();
                BeanUtil.copyProperties(paymentEditAttrUpdateDTO, paymentUpdateBatchDTO);
                paymentUpdateBatchDTO.setPaymenrUpdateList(paymentUpdateList);
                updateBatch(paymentUpdateBatchDTO);
            }

            // 批量编辑日志
            List<String> updataItemList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            List<Long> dataIdList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            for (PaymentEntityExt item : paymentEntityList) {
                dataIdList.add(item.getId());
                String serialNo = item.getSerialNo();
                updataItemList.add(serialNo);
            }
            String updataItem = StringUtils.join(updataItemList, "，");
            String userId = paymentEditAttrUpdateDTO.getUserId();
            String loginUserName = paymentEditAttrUpdateDTO.getLoginUserName();
            // 标签特殊处理
            Integer fieldType = paymentEditAttrUpdateDTO.getFieldType();
            Boolean isFieldDependence = paymentEditAttrUpdateDTO.getIsFieldDependence();
            logHelp.analysisLabel(corpid, fieldType, isFieldDependence,paymentEditAttrUpdateDTO.getLogFieldEditedList());

            String changedLogItemsStr = logHandleHelp.getChangedLogItemsStr(paymentEditAttrUpdateDTO.getLogFieldEditedList());
            if(dataIdList.size() > 1 ){
                String memo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_UPDATE_FORM_DATA_BATCH_ATTR), loginUserName, XbbRefTypeEnum.PAYMENT.getName(),
                        changedLogItemsStr, dataIdList.size());
                List<InfoArrPojo> infoArrPojoList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                InfoArrPojo infoArrPojo = new InfoArrPojo();
                infoArrPojo.setTitle(XbbRefTypeEnum.PAYMENT.getName());
                infoArrPojo.setContent(updataItem);
                infoArrPojoList.add(infoArrPojo);
                mongoLogHelp.buildLog4InfoArr(infoArrPojoList, corpid, userId, loginUserName, OperateModuleTypeEnum.PaymentManage, OperateTypeEnum.EDIT,
                        "", "", memo, paymentEditAttrUpdateDTO.getHttpHeader());
            } else if (Objects.equals(dataIdList.size(), 1)){
                String memo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_USER_UPDATE_FORM_DATA_ATTR), loginUserName, XbbRefTypeEnum.PAYMENT.getName(), updataItem,
                        changedLogItemsStr);
                mongoLogHelp.buildLog(corpid, userId, loginUserName, OperateModuleTypeEnum.PaymentManage, OperateTypeEnum.EDIT,
                        dataIdList.get(0).toString(), updataItem, memo, paymentEditAttrUpdateDTO.getHttpHeader());
            }
        } catch (XbbException e) {
            throw e;
        } catch (Exception e) {
            LOG.error("paymentService.batchEditAttr 执行出错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
    }


    @Override
    public PaymentVO badDebtReturn(PaymentReturnDTO paymentReturnDTO) throws XbbException {
        Long paymentId = paymentReturnDTO.getDataId();
        String corpid = paymentReturnDTO.getCorpid();
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery("corpid.keyword",corpid));
        boolQueryBuilder.filter(termQuery(StringConstant.DEL,DelEnum.NORMAL.getDel()));
        boolQueryBuilder.filter(termsQuery(PaymentSheetEnum.getEsAttr4Keyword(PaymentSheetEnum.PAYMENT),Arrays.asList(paymentId)));
        boolQueryBuilder.filter(termQuery(PaymentSheetEnum.getEsAttr4Keyword(PaymentSheetEnum.PAYMENT_SHEET_TYPE), PaymentSheetTypeEnum.BAD_PAYMENT.getCode()));
        boolQueryBuilder.filter(termsQuery(BasicConstant.ALONE,Arrays.asList(SheetAloneEnum.PARENT.getCode(), SheetAloneEnum.NORMAL.getCode())));
        List<PaasFormDataEntityExt> paasFormDataEntityExtList = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_PAYMENT_SHEET,boolQueryBuilder,PaasFormDataEntityExt.class,null);
        if (paasFormDataEntityExtList.isEmpty()){
            return new PaymentVO();
        }
        PaasFormDataEntityExt paasFormDataEntityExt = paasFormDataEntityExtList.get(0);
        FormDataDeleteBatchDTO formDataDeleteBatchDTO = new FormDataDeleteBatchDTO();
        BeanUtil.copyProperties(paymentReturnDTO, formDataDeleteBatchDTO);
        BeanUtil.copyProperties(paasFormDataEntityExt,formDataDeleteBatchDTO);
        formDataDeleteBatchDTO.setSaasMark(SaasMarkEnum.SAAS.getCode());
        formDataDeleteBatchDTO.setBusinessType(XbbRefTypeEnum.PAYMENT_SHEET.getCode());
        formDataDeleteBatchDTO.setDataIdList(Collections.singletonList(paasFormDataEntityExt.getDataId()));
        saasDeleteHelp.deleteBatch(formDataDeleteBatchDTO);
//        paymentSheetService.delPaymentSheet(Collections.singletonList(paymentId),corpid);
//        PaymentEntityExt paymentEntityExt = paymentModel.getByKey(paymentId, corpid);
//        if (Objects.isNull(paymentEntityExt)) {
//            throw new XbbException(PaymentErrorCodeEnum.API_ERROR_208001);
//        }
//        String status = FastJsonHelper.getStringOrDefaultFromFormData(paymentEntityExt.getData(), PaymentEnum.STATUS.getAttr(), PaymentStatusEnum.UNKNOWN.getCode());
//        if (!Objects.equals(status, PaymentStatusEnum.BAD_DEBT.getCode()) && !Objects.equals(status, PaymentStatusEnum.PARTIAL_BAD_DEBT.getCode())) {
//            throw new XbbException(PaymentErrorCodeEnum.API_ERROR_208012.getCode(), String.format(PaymentErrorCodeEnum.API_ERROR_208012.getMsg(), SaasButtonEnum.RETURN.getValue()));
//        }
//        Map<String, Object> dataParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
//        dataParam.put(PaymentSheetEnum.IS_BAD.getAttr(), BasicConstant.ONE);
//        dataParam.put(PaymentSheetEnum.PAYMENT.getAttr(), paymentId);
//        Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
//        param.put(ParameterConstant.CORPID, corpid);
//        param.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
//        List<PaasFormDataEntityExt> paasFormDataEntityExts = jsonSetService.selectByCondition(XbbRefTypeEnum.PAYMENT_SHEET.getCode(), dataParam, param);
//        if (paasFormDataEntityExts.isEmpty()) {
//            String realStatus = Objects.equals(status, PaymentStatusEnum.BAD_DEBT.getCode()) ? PaymentStatusEnum.UN_RECEIVABLES.getCode() : Objects.equals(status, PaymentStatusEnum.PARTIAL_BAD_DEBT.getCode()) ? PaymentStatusEnum.PARTIAL_RECEIPTS.getCode() : status;
//            jsonSetService.jsonSetById(XbbRefTypeEnum.PAYMENT.getCode(), corpid, paymentId, PaymentEnum.STATUS.getAttr(), realStatus);
//        } else {
//            PaasFormDataEntityExt paasFormDataEntityExt = paasFormDataEntityExts.get(BasicConstant.ZERO);
//            PaymentSheetEntityExt paymentSheetEntityExt = new PaymentSheetEntityExt();
//            BeanUtil.copyProperties(paasFormDataEntityExt, paymentSheetEntityExt);
//            paymentSheetEntityExt.setDel(DelEnum.DELETE.getDel());
//            paymentSheetModel.save(paymentSheetEntityExt);
//            dataParam.remove(PaymentSheetEnum.IS_BAD.getAttr());
//            List<PaasFormDataEntityExt> sheets = jsonSetService.selectByCondition(XbbRefTypeEnum.PAYMENT_SHEET.getCode(), dataParam, param);
//            if (sheets.size() > BasicConstant.ZERO) {
//                jsonSetService.jsonSetById(XbbRefTypeEnum.PAYMENT.getCode(), corpid, paymentId, PaymentEnum.STATUS.getAttr(), PaymentStatusEnum.PARTIAL_RECEIPTS.getCode());
//            } else {
//                jsonSetService.jsonSetById(XbbRefTypeEnum.PAYMENT.getCode(), corpid, paymentId, PaymentEnum.STATUS.getAttr(), PaymentStatusEnum.UN_RECEIVABLES.getCode());
//            }
//        }
        return new PaymentVO();
    }

    @Override
    public List<PaasFormDataEntityExt> getPaymentEsDataListByContractId(String corpid, Long contractId) throws XbbException {
        return paymentModel.getPaymentEsDataListByLinkId(corpid, contractId, PaymentEnum.CONTRACT, PaasFormDataEntityExt.class);
    }

    @Override
    public List<PaasFormDataEntityExt> getPaymentEsDataListByCustomerId(String corpid, Long customerId) throws XbbException {
        return paymentModel.getPaymentEsDataListByLinkId(corpid, customerId, PaymentEnum.CUSTOMER, PaasFormDataEntityExt.class);
    }

    /**
     * 获取回款单数量和金额
     * @param corpid
     * @param paymentIdIn
     * @throws XbbException
     * @author long.rao
     * @date 2019-03-26 11:00
     */
    private Map<Long, JSONObject> getPaymentSheetNumAndTotalAmount(String corpid, List<Long> paymentIdIn) throws XbbException{
        //返回的Map
        Map<Long, JSONObject> retMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery("corpid.keyword",corpid));
        boolQueryBuilder.filter(termsQuery("data." + PaymentSheetEnum.PAYMENT.getAttr(), paymentIdIn));
        boolQueryBuilder.filter(termQuery("del", DelEnum.NORMAL.getDel()));
        List<String> fieldList = new ArrayList<>();
        fieldList.add(PaymentSheetEnum.getAttrConnectData(PaymentSheetEnum.PAYMENT));
        fieldList.add(PaymentSheetEnum.getAttrConnectData(PaymentSheetEnum.AMOUNT));
        List<PaasFormDataEntityExt> paymentSheets = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_PAYMENT_SHEET,boolQueryBuilder,PaasFormDataEntityExt.class, fieldList);

        for (PaasFormDataEntityExt sheet : paymentSheets) {
            JSONObject data = sheet.getData();
            Long paymentId = FastJsonHelper.getLongOrDefaultFromFormData(data, PaymentSheetEnum.PAYMENT.getAttr(), 0L);
            Double amount = getDoubleOrDefaultFromFormData(data, PaymentSheetEnum.AMOUNT.getAttr(), 0D);
            if (retMap.containsKey(paymentId)) {
                JSONObject numAndAmount = retMap.get(paymentId);
                Integer num = numAndAmount.getInteger("num");
                Double realPayment = numAndAmount.getDouble("realPayment");
                num++;
                realPayment += amount;
                numAndAmount.put("num", num);
                numAndAmount.put("realPayment", realPayment);
            } else {
                JSONObject numAndAmount = new JSONObject();
                Integer num = 1;
                numAndAmount.put("num", num);
                numAndAmount.put("realPayment", amount);
                retMap.put(paymentId, numAndAmount);
            }
        }

        return retMap;
    }

    @Override
    public PaymentUpdateBatchVO updateBatch(PaymentUpdateBatchDTO paymentUpdateBatchDTO) throws XbbException {
        PaymentUpdateBatchVO paymentUpdateBatchVO = new PaymentUpdateBatchVO();
        try {
            String corpid = paymentUpdateBatchDTO.getCorpid();
            List<UpdateDataEntity> updateList = new ArrayList<>();
            List<PaymentUpdateDTO> paymenrUpdateList = paymentUpdateBatchDTO.getPaymenrUpdateList();
            if (Objects.nonNull(paymenrUpdateList) && !paymenrUpdateList.isEmpty()) {
                paymenrUpdateList.forEach((item)->{
                    updateList.add(ExplainUtil.getUpdateData(item.getId(), item.getData(), corpid));
                });
            }
            if (!updateList.isEmpty()) {
                paymentModel.updateBatch(updateList, corpid);
            }

        } catch (Exception e) {
            LOG.error("PaymentServiceImpl.updateBatch 执行出错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        return paymentUpdateBatchVO;
    }

    @Override
    public void dataConsistencyUpdateCustomer(String corpid, Long customerId, String customerName) throws XbbException {
        try {
            BoolQueryBuilder filter = boolQuery()
                    .filter(termQuery("corpid.keyword", corpid))
                    .filter(termQuery("del", 0))
                    .filter(termQuery(PaymentEnum.getEsAttr4Keyword(PaymentEnum.CUSTOMER), customerId));
            List<String> fieldList = new ArrayList<>();
            fieldList.add(FieldTypeEnum.DATAID.getAlias());
            List<PaasFormDataEntityExt> esEntities = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_PAYMENT, filter, PaasFormDataEntityExt.class, fieldList);
            Set<Long> ids = new HashSet<>();
            for (PaasFormDataEntityExt esEntity : esEntities) {
                ids.add(esEntity.getDataId());
            }
            Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            param.put("corpid", corpid);
            param.put("idIn", ids);
            param.put("del", 0);
            List<PaymentEntityExt> paymentEntityExtList = paymentModel.findEntitys(param);

            if (Objects.nonNull(paymentEntityExtList) && !paymentEntityExtList.isEmpty()) {
                List<PaymentUpdateDTO> paymentUpdateDTOList = new ArrayList<>();
                for (PaymentEntityExt entityExt : paymentEntityExtList) {
                    PaymentUpdateDTO paymentUpdateDTO = new PaymentUpdateDTO();
                    paymentUpdateDTO.setId(entityExt.getId());
                    JSONObject data = new JSONObject();
                    data.put(PaymentEnum.CUSTOMER_LINK_TEXT.getAttr(), customerName);
                    paymentUpdateDTO.setData(data);
                    paymentUpdateDTOList.add(paymentUpdateDTO);
                }
                PaymentUpdateBatchDTO paymentUpdateBatchDTO = new PaymentUpdateBatchDTO();
                paymentUpdateBatchDTO.setCorpid(corpid);
                paymentUpdateBatchDTO.setPaymenrUpdateList(paymentUpdateDTOList);
                updateBatch(paymentUpdateBatchDTO);
            }
        } catch (Exception e) {
            LOG.error("PaymentServiceImpl.dataConsistencyUpdateCustomer 出错，  corpid=" + corpid + "  customerId=" + customerId + " customerName=" + customerName, e);
        }
    }

    @Override
    public void dataConsistencyUpdateContract(String corpid, Long contractId, String contractName) throws XbbException {
        try {
            BoolQueryBuilder filter = boolQuery()
                    .filter(termQuery("corpid.keyword", corpid))
                    .filter(termQuery("del", 0))
                    .filter(termQuery(PaymentEnum.getEsAttr4Keyword(PaymentEnum.CONTRACT), contractId));
            List<String> fieldList = new ArrayList<>();
            fieldList.add(FieldTypeEnum.DATAID.getAlias());
            List<PaasFormDataEntityExt> esEntities = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_PAYMENT, filter, PaasFormDataEntityExt.class, fieldList);
            Set<Long> ids = new HashSet<>();
            for (PaasFormDataEntityExt esEntity : esEntities) {
                ids.add(esEntity.getDataId());
            }
            Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            param.put("corpid", corpid);
            param.put("idIn", ids);
            param.put("del", 0);
            List<PaymentEntityExt> paymentEntityExtList = paymentModel.findEntitys(param);

            if (Objects.nonNull(paymentEntityExtList) && !paymentEntityExtList.isEmpty()) {
                List<PaymentUpdateDTO> paymentUpdateDTOList = new ArrayList<>();
                for (PaymentEntityExt entityExt : paymentEntityExtList) {
                    PaymentUpdateDTO paymentUpdateDTO = new PaymentUpdateDTO();
                    paymentUpdateDTO.setId(entityExt.getId());
                    JSONObject data = new JSONObject();
                    data.put(PaymentEnum.CONTRACT_LINK_TEXT.getAttr(), contractName);
                    paymentUpdateDTO.setData(data);
                    paymentUpdateDTOList.add(paymentUpdateDTO);
                }
                PaymentUpdateBatchDTO paymentUpdateBatchDTO = new PaymentUpdateBatchDTO();
                paymentUpdateBatchDTO.setCorpid(corpid);
                paymentUpdateBatchDTO.setPaymenrUpdateList(paymentUpdateDTOList);
                updateBatch(paymentUpdateBatchDTO);
            }
        } catch (Exception e) {
            LOG.error("OpportunityServiceImpl.dataConsistencyUpdateContract 出错， corpid=" + corpid + "  contractId=" + contractId + "  contractName=" + contractName, e);
        }
    }

    @Override
    public void updateRollback(Collection<Long> idIn, String corpid) throws XbbException {
        if (Objects.isNull(idIn) || idIn.isEmpty()) {
            return;
        }
        Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put("idIn", idIn);
        param.put(StringConstant.CORPID, corpid);
        List<PaymentEntityExt> payments = paymentModel.findEntitysWithoutSub(param);
        updateRollback(payments, corpid);
        //同步回滚对账记录
        customerStatementService.updateRollback(corpid, XbbRefTypeEnum.PAYMENT.getCode(), idIn);
    }

    @Override
    public void updateRollback(List<PaymentEntityExt> payments, String corpid) throws XbbException {
        if (CollectionUtils.isNotEmpty(payments)) {
            for (PaymentEntityExt item : payments) {
                PaasFormDataEntity paasFormDataEntity = new PaasFormDataEntity();
                BeanUtil.copyProperties(item, paasFormDataEntity);
                proEsHelper.reductionEsInUpdate(paasFormDataEntity, item.getId(), corpid, IndexTypeEnum.IDX_SAAS_PAYMENT);
            }
        }
    }

    /**
     * 应收款导入
     *
     * @param importFormDataDTO
     * @param titlePojoList
     * @param rowGroupPojo
     * @param fieldAttrList
     * @return
     * @throws XbbException
     * @author chenshan
     * @date 2019-11-04 14:51
     */
    @Override
    public FormDataAddDTO formatExcelValue(ImportFormDataDTO importFormDataDTO, List<CellTitlePojo> titlePojoList, RowGroupPojo rowGroupPojo, List<FieldAttrEntityForImport> fieldAttrList) throws XbbException {
        FormDataAddDTO formDataAddDTO = new FormDataAddDTO();
        BeanUtil.copyProperties(importFormDataDTO, formDataAddDTO);
        // data 数据
        JSONObject dataJson = new JSONObject();
        Long linkCustomerId = 0L;
        List<List<CellValuePojo>> rowValueList = rowGroupPojo.getRowValueList();
        // 分组的第一条数据作为给实体对象赋值的数据
        List<CellValuePojo> cellValueList = rowValueList.get(0);

        FieldAttrEntityForImport linkCustomerIdAttr = null;
        for (FieldAttrEntityForImport fieldAttrEntityForImport : fieldAttrList) {
            if (Objects.equals(fieldAttrEntityForImport.getAttr(), PaymentEnum.CUSTOMER.getAttr())) {
                linkCustomerIdAttr = fieldAttrEntityForImport;
                break;
            }
        }

        if (Objects.nonNull(linkCustomerIdAttr)) {
            linkCustomerId = importHelper.formatLinkCustomer2CustomerId(titlePojoList, dataJson, rowValueList, linkCustomerIdAttr);
            if ( Objects.equals(linkCustomerId, 0L) ) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.PLEASE_ENTER, linkCustomerIdAttr.getAttrName());
            }
        }

        // 遍历数据
        for ( FieldAttrEntityForImport fieldAttrEntityForImport : fieldAttrList ) {
            String attr = fieldAttrEntityForImport.getAttr();
            Integer fieldType = fieldAttrEntityForImport.getFieldType();
            String attrName = fieldAttrEntityForImport.getAttrName();
            Integer columnIndex = importHelper.getColumnIndexByTitle(titlePojoList, attrName, null);
            Object cellValue = importHelper.getValueByColumnIndex(cellValueList, columnIndex);
            if (Objects.equals(attr, PaymentEnum.CUSTOMER.getAttr())) {

            } else if ( Objects.equals(fieldType, FieldTypeEnum.SUB_FORM.getType()) ) {
                importHelper.formatSubFormValue4Import(rowValueList, titlePojoList, importFormDataDTO, fieldAttrEntityForImport, dataJson);
            } else {
                if ( Objects.isNull(cellValue) || StringUtil.isEmpty(cellValue.toString()) ) {
                    continue;
                }
                if ( ImportHelper.commonHandleFieldType.contains(fieldAttrEntityForImport.getFieldType()) ) {
                    importHelper.formatCommonField(dataJson, fieldAttrEntityForImport, cellValue);
                } else if (Objects.equals(attr, PaymentEnum.CONTRACT.getAttr()) ) {
                    importHelper.formatRelyBusiness(linkCustomerId, dataJson, fieldAttrEntityForImport, cellValue, ContractEnum.LINK_CUSTOMER.getAttr());
                } else {
                    if ( Objects.equals(fieldType, FieldTypeEnum.SERIALNO.getType()) ) {
                        formDataAddDTO.setSerialNo(cellValue.toString());
                    } else if (Objects.equals(fieldType, FieldTypeEnum.LINK_DATA.getType())) {
                        importHelper.formatLinkData(cellValue, fieldAttrEntityForImport, dataJson);
                    } else if (Objects.equals(fieldType, FieldTypeEnum.LINK_DATA_MULTI.getType())) {
                        importHelper.formatLinkDataMulti(cellValue, importFormDataDTO, fieldAttrEntityForImport, dataJson);
                    } else {
                        dataJson.put(attr, cellValue);
                    }
                }
            }
        }
        formDataAddDTO.setDataList(dataJson);
        return formDataAddDTO;
    }

    @Override
    public SheetAmountDetailGetVO paymentAmountDetailGet(boolean sumFlag, SheetAmountDetailGetDTO sheetAmountDetailGetDTO) throws XbbException {
        Integer businessType = sheetAmountDetailGetDTO.getBusinessType();
        String corpid = sheetAmountDetailGetDTO.getCorpid();
        List<Long> dataIdList = sheetAmountDetailGetDTO.getDataIdList();
        PaymentSheetTypeEnum paymentSheetTypeEnum = PaymentSheetTypeEnum.getByBusinessType(businessType);
        boolean isRedFlag = PaymentSheetTypeEnum.isRed(paymentSheetTypeEnum.getCode());
        //默认读取应收款/合同的未收款，但是红冲已核销、红冲预收款核销时需要读取应收款/合同的已收（红冲预收款不会关联合同和应收款，不会调用该接口）
        PaymentEnum paymentEnum = PaymentEnum.UN_AMOUNT;
        ContractEnum contractEnum = ContractEnum.UN_FINISH_AMOUNT;
        if (isRedFlag) {
            paymentEnum = REAL_AMOUNT;
            contractEnum = ContractEnum.FINISH_AMOUNT;
        }
        if (sumFlag) {
            //只计算总额，不用封装明细，但是要从每条应收款内求和得到已收/未收总额
            return getResult4AmountDetailSum(isRedFlag, sheetAmountDetailGetDTO, dataIdList, paymentEnum, contractEnum, corpid);
        } else {
            //除了得到总额，还要处理明细-按顺序封装明细内所有东西：签订人、金额、合同名、应收款名等
            return getResult4AmountDetail(corpid, isRedFlag, sheetAmountDetailGetDTO, dataIdList, paymentEnum, contractEnum);
        }
    }

    @Override
    public RelationshipGetVO getContractOrPaymentOrPaymentSheetInfo(RelationshipGetDTO relationshipGetDTO) {
        RelationshipGetVO relationshipGetVO = new RelationshipGetVO();
        Map<Long, RelationshipGetPojo> contractMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long, RelationshipGetPojo> paymentMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long, RelationshipGetPojo> paymentSheetMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put("invoiceId", relationshipGetDTO.getInvoiceId());
        param.put(StringConstant.CORPID, relationshipGetDTO.getCorpid());
        param.put(InvoiceEnum.IS_CANCEL.getSaasAttr(), BasicConstant.ZERO);
        param.put(StringConstant.DEL, DelEnum.NORMAL.getDel());
        Integer type = RefTypeEnum.CONTRACT.getCode();
        List<Object> valueList = new ArrayList<>();
        Set<Object> contractList = new HashSet<>();
        List<InvoiceRelationshipEntity> invoiceRelationshipEntityList = invoiceRelationshipModel.findEntitys(param);
        for (InvoiceRelationshipEntity invoiceRelationshipEntity : invoiceRelationshipEntityList) {
            RelationshipGetPojo relationshipGetPojo = new RelationshipGetPojo();
            BeanUtil.copyProperties(invoiceRelationshipEntity, relationshipGetPojo);
            contractMap.put(invoiceRelationshipEntity.getContractId(), relationshipGetPojo);
            contractList.add(invoiceRelationshipEntity.getContractId());
            if (relationshipGetPojo.getPaymentId() != null) {
                if (relationshipGetPojo.getPaymentId().intValue() > BasicConstant.ONE) {
                    type = RefTypeEnum.PAYMENT.getCode();
                    valueList.add(invoiceRelationshipEntity.getPaymentId());
                    paymentMap.put(invoiceRelationshipEntity.getPaymentId(), relationshipGetPojo);
                }
            } else if (relationshipGetPojo.getPaymentSheetId() != null) {
                if (relationshipGetPojo.getPaymentSheetId().intValue() > BasicConstant.ONE) {
                    type = RefTypeEnum.PAYMENTSHEET.getCode();
                    valueList.add(invoiceRelationshipEntity.getPaymentSheetId());
                    paymentSheetMap.put(invoiceRelationshipEntity.getPaymentSheetId(), relationshipGetPojo);
                }
            }
        }
        List<ContractEntityExt> contractEntityExtList = null;
        List<PaymentEntityExt> paymentEntityExtList = null;
        List<PaymentSheetEntityExt> paymentSheetEntityExtList = null;
        List<RelationshipGetPojo> relationshipGetPojos = new ArrayList<>();
        param.put(StringConstant.IDIN, new ArrayList<>(contractList));
        contractEntityExtList = contractModel.findEntitys(param);
        for (ContractEntityExt contractEntityExt : contractEntityExtList) {
            JSONObject data = contractEntityExt.getData();
            RelationshipGetPojo relationshipGetPojo = contractMap.get(contractEntityExt.getId());
            relationshipGetPojo.setContractAmount(data.getDouble(ContractEnum.AMOUNT.getAttr()));
            relationshipGetPojo.setContractInvoiceAmount(data.getDouble(ContractEnum.INVOICE_AMOUNT.getAttr()));
            relationshipGetPojos.add(relationshipGetPojo);
        }
        if (Objects.equals(RefTypeEnum.PAYMENT.getCode(), type)) {
            param.put(StringConstant.IDIN, valueList);
            paymentEntityExtList = paymentModel.findEntitys(param);
            for (PaymentEntityExt paymentEntityExt : paymentEntityExtList) {
                JSONObject data = paymentEntityExt.getData();
                RelationshipGetPojo relationshipGetPojo = paymentMap.get(paymentEntityExt.getId());
                relationshipGetPojo.setPaymentAmount(data.getDouble(PaymentEnum.AMOUNT.getAttr()));
                relationshipGetPojo.setPaymentInvoiceAmount(data.getDouble(PaymentEnum.INVOICE_AMOUNT.getAttr()));
                relationshipGetPojos.add(relationshipGetPojo);
            }
        } else if (Objects.equals(RefTypeEnum.PAYMENTSHEET.getCode(), type)) {
            param.put(StringConstant.IDIN, valueList);
            paymentSheetEntityExtList = paymentSheetModel.findEntitys(param);
            for (PaymentSheetEntityExt paymentSheetEntityExt : paymentSheetEntityExtList) {
                JSONObject data = paymentSheetEntityExt.getData();
                RelationshipGetPojo relationshipGetPojo = paymentSheetMap.get(paymentSheetEntityExt.getId());
                relationshipGetPojo.setPaymentSheetAmount(data.getDouble(PaymentSheetEnum.AMOUNT.getAttr()));
                relationshipGetPojo.setPaymentSheetInvoiceAmount(data.getDouble(PaymentSheetEnum.INVOICE_AMOUNT.getAttr()));
                relationshipGetPojos.add(relationshipGetPojo);
            }
        }
        relationshipGetVO.setList(relationshipGetPojos);
        return relationshipGetVO;
    }

    /**
     * 查询合同信息，并处理构建合同id和合同一些信息的对应关系map，以及签订人userId和签订人名称对应关系map
     * @param corpid 公司id
     * @param dataIdList 合同id集合
     * @param cidSignPersonMap 合同id-签订人userId
     * @param cidMap 合同id-合同信息
     * @return java.util.Map<java.lang.String,java.lang.String>
     * @throws XbbException
     * @author zcp
     * @date 19/11/19 019 16:25
     * @update 19/11/19 019 16:25
     * @since v1.0
     * @version v1.0
     */
    private Map<String, String> handleContractInfo(String corpid, List<Long> dataIdList, Map<Long, String> cidSignPersonMap, Map<Long, PaasFormDataEntityExt> cidMap) throws XbbException {
        List<String> fieldList = Arrays.asList("id", ContractEnum.CONTRACT_NO.getAttr(), ContractEnum.getAttrConnectData(ContractEnum.AMOUNT), ContractEnum.getAttrConnectData(ContractEnum.FINISH_AMOUNT), ContractEnum.getAttrConnectData(ContractEnum.UN_FINISH_AMOUNT), ContractEnum.getAttrConnectData(ContractEnum.SIGN_PERSON));
        List<PaasFormDataEntityExt> contracts = formHelp.getFormListByIds4All(corpid, IndexTypeEnum.IDX_SAAS_CONTRACT, dataIdList, fieldList);
        Set<String> signUserIds = new HashSet<>();
        for (PaasFormDataEntityExt entityExt : contracts) {
            String signUserId = FastJsonHelper.getStringOrDefaultFromFormData(entityExt.getData(), ContractEnum.SIGN_PERSON.getAttr(), "-1");
            signUserIds.add(signUserId);
            cidSignPersonMap.put(entityExt.getId(), signUserId);
            cidMap.put(entityExt.getId(), entityExt);
        }
        //签订人userId-签订人姓名
        return commonHelp.getUserNameMapByIds(corpid, signUserIds);
    }

    /**
     * 资金管理应收款关联红冲回款单
     *
     * @param corpid    用户信息
     * @param paymentId 应收款id
     * @param aloneList
     * @return 红冲应收款
     * @throws XbbException 异常
     */
    @Override
    public List<PaasFormDataEntityExt> getAssociationRedSheetListByAlone(String corpid, Long paymentId, List<Integer> aloneList) throws XbbException {
        List<PaasFormDataEntityExt> paasFormDataESList = new ArrayList<>();
        Map<String,Object> modelMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        modelMap.put(ParameterConstant.CORPID, corpid);
        modelMap.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
        List<PaasFormDataEntityExt> paasFormDataEntityExts = paasEsModel.selectByOneCondition(XbbRefTypeEnum.PAYMENT.getCode(), PaymentEnum.ORIGIN_ID.getAttr(), paymentId.toString(), modelMap, IndexTypeEnum.IDX_SAAS_PAYMENT);
        List<Object> redPaymentIdIn = new ArrayList<>();
        paasFormDataEntityExts.forEach(paasFormDataEntityExt -> redPaymentIdIn.add(paasFormDataEntityExt.getId()));
        if (!redPaymentIdIn.isEmpty()) {
            List<ConditionsEntityExt > conditions = new ArrayList<>();
            conditions.add(EsUtil.packageContions(PaymentSheetEnum.PAYMENT.getAttr(), redPaymentIdIn, ConditionEnum.IN, FieldTypeEnum.TEXT.getType()));
            conditions.add(EsUtil.packageContions(PaymentSheetEnum.PAYMENT_SHEET_TYPE.getAttr(), Arrays.asList(PaymentSheetTypeEnum.RED_WRITE_OFF.getCode(), PaymentSheetTypeEnum.RED_WRITE_OFF_PREPAYMENT.getCode(), PaymentSheetTypeEnum.RED_WRITE_OFF_BALANCE.getCode()), ConditionEnum.IN, FieldTypeEnum.TEXT.getType()));
            PaasFormDataEsListVO paasFormDataEsListVO = saasDetailTabService.getEsListOnlyByCondition(corpid, XbbRefTypeEnum.PAYMENT_SHEET.getCode(), conditions);
            paasFormDataESList = paasFormDataEsListVO.getPaasFormDataESList();
        }
        return paasFormDataESList;
    }

    @Override
    public HandleLinkInfoVO handlePayment(PaymentSheetTypeEnum paymentSheetTypeEnum, JSONObject sheetData, String corpid, Map<Long, Double> paymentIdToAmount, Set<Long> paymentIds) throws XbbException {
        Long sheetPaymentTime = sheetData.getLong(PaymentSheetEnum.PAYMENT_TIME.getAttr());
        Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put("idIn", paymentIds);
        param.put("corpid", corpid);
        List<PaymentEntityExt> payments = paymentModel.findEntitys(param);
        if (Objects.isNull(payments)) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_DATA_NOT_EXIST);
        }
        List<UpdateDataEntity> updateList = new ArrayList<>();
        Map<Long, Long> idModelTypeMap = new HashMap<>(payments.size());
        boolean isRedFlag = PaymentSheetTypeEnum.isRed(paymentSheetTypeEnum.getCode());
        boolean isBadFlag = PaymentSheetTypeEnum.isBad(paymentSheetTypeEnum.getCode());
        for (PaymentEntityExt paymentEntityExt : payments) {
            String name = paymentEntityExt.getSerialNo();
            if (Objects.equals(paymentEntityExt.getDel(), DelEnum.DELETE.getDel())) {
                throw new XbbException(PaymentErrorCodeEnum.API_ERROR_208032, PaymentErrorCodeEnum.API_ERROR_208032.getMsg(), XbbRefTypeEnum.PAYMENT.getName(), name);
            }
            Long paymentId = paymentEntityExt.getId();
            //当前应收款的实收金额(新增)
            Double value = paymentIdToAmount.getOrDefault(paymentId, 0D);
            if (value == 0) {
                continue;
            }
            JSONObject data = paymentEntityExt.getData();
            Double tempAmount = value;
            Double planRealAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(data, REAL_AMOUNT.getAttr(), 0D);
            Double unAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(data, PaymentEnum.UN_AMOUNT.getAttr(), 0D);
            //红冲应收金额
            Double redAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(data, PaymentEnum.RED_AMOUNT.getAttr(), 0D);
            JSONObject updateData = new JSONObject();
            if (isRedFlag) {
                if (Arith.sub(tempAmount , planRealAmount) > ConfigConstant.amountAccuracy) {
                    //红冲，限制红冲金额小于等于回款金额
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.DETAIL_BEYOND_AMOUNT_RED, XbbRefTypeEnum.PAYMENT.getName() + name);
                }
                //红冲的，把金额置为负数。用tempAmount计算金额是否合法
                value = Arith.mul(value, -1);
                updateData.put(PaymentEnum.HAS_RED.getAttr(), HasRedEnum.HAS_RED.getCode());
            } else {
                //普通回款（已核销、预收款核销、坏账），限制回款金额小于等于未收金额
                if (Arith.sub(value , unAmount) > ConfigConstant.amountAccuracy) {
                    if (isBadFlag) {
                        throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.DETAIL_BEYOND_AMOUNT_BAD, XbbRefTypeEnum.PAYMENT.getName(), name);
                    }
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.DETAIL_BEYOND_AMOUNT, XbbRefTypeEnum.PAYMENT.getName(), name);
                }
                if (!isBadFlag) {
                    //坏账，红冲不需要置应收款的实际收款日期，只有已核销、预收款核销才需要
                    Long realPayTime = data.getLongValue(PaymentEnum.REAL_PAY_TIME.getAttr());
                    if (realPayTime < sheetPaymentTime) {
                        updateData.put(PaymentEnum.REAL_PAY_TIME.getAttr(), sheetPaymentTime);
                    }
                }
            }
            //处理应收款的已收、未收、回款状态
            Double planAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(data, PaymentEnum.AMOUNT.getAttr(), 0D);
            Double badAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(data, PaymentEnum.BAD_AMOUNT.getAttr(), 0D);
            handlePlanAmountStatus4Add(isBadFlag, value, updateData, planAmount, planRealAmount, unAmount, badAmount, redAmount);
            UpdateDataEntity updateDataEntity = ExplainUtil.getUpdateData(paymentId, updateData, corpid);
            updateList.add(updateDataEntity);
            idModelTypeMap.put(paymentId, paymentEntityExt.getSysLong10());
        }
        return new HandleLinkInfoVO(updateList, idModelTypeMap);
    }

    @Override
    public List<UpdateDataEntity> updatePayment4Del(String corpid, Set<String> errorTypeSet, Set<String> errorDataSet, Collection<Long> delIdList, SheetDeleteHandleRelateDTO sheetDeleteHandleRelateDTO) throws XbbException {
        Map<Long, Double> paymentIdToAmount = sheetDeleteHandleRelateDTO.getPaymentIdToAmount();
        Map<Long, Double> paymentIdToUnAmount = sheetDeleteHandleRelateDTO.getPaymentIdToUnAmount();
        Map<Long, Double> paymentIdToBad = sheetDeleteHandleRelateDTO.getPaymentIdToBad();
        Set<Long> paymentIds = sheetDeleteHandleRelateDTO.getPaymentIds();
        Map<Long, List<Long>> pidSheetIdListMap = sheetDeleteHandleRelateDTO.getPidSheetIdListMap();
        Map<Long, List<String>> pidSheetNoListMap = sheetDeleteHandleRelateDTO.getPidSheetNoListMap();
        List<String> delNoList = sheetDeleteHandleRelateDTO.getDelNoList();
        PaymentEnum enumAmount = PaymentEnum.AMOUNT;
        PaymentEnum enumRealAmount = REAL_AMOUNT;
        PaymentEnum enumUnAmount = PaymentEnum.UN_AMOUNT;
        PaymentEnum enumBadAmount = PaymentEnum.BAD_AMOUNT;
        PaymentEnum enumRealPayTime = PaymentEnum.REAL_PAY_TIME;
        List<String> fieldList = Arrays.asList(BasicConstant.ID, "del", PaymentEnum.PAYMENT_NO.getAttr(), PaymentEnum.getAttrConnectData(enumAmount), PaymentEnum.getAttrConnectData(enumRealAmount), PaymentEnum.getAttrConnectData(enumUnAmount), PaymentEnum.getAttrConnectData(enumBadAmount), PaymentEnum.getAttrConnectData(enumRealPayTime));
        List<PaasFormDataEntityExt> payments = formHelp.getFormListByIds4All(corpid, IndexTypeEnum.IDX_SAAS_PAYMENT, paymentIds, fieldList);
        List<UpdateDataEntity> updateList = new ArrayList<>();
        if (Objects.isNull(payments)) {
            //查不到关联数据，则不关联更新
            return updateList;
        }
        //再查询出除了allDelIdList之外关联了paymentIds的回款单（无父子、父回款单）
        String attrSheetType = PaymentSheetEnum.getAttrConnectData(PaymentSheetEnum.PAYMENT_SHEET_TYPE);
        String attrPlan = PaymentSheetEnum.getAttrConnectData(PaymentSheetEnum.PAYMENT);
        List<String> notBadCodeList = PaymentSheetTypeEnum.getNotBadCodeList();
        Map<Long, List<PaasFormDataEntityExt>> sheetMap = formHelp.getSheetListMap(corpid, delIdList, paymentIds, IndexTypeEnum.IDX_SAAS_PAYMENT_SHEET, attrSheetType, attrPlan, notBadCodeList);
        PaymentSheetEnum enumSheetPaymentTime = PaymentSheetEnum.PAYMENT_TIME;
        for (PaasFormDataEntityExt entityExt : payments) {
            if (Objects.equals(entityExt.getDel(), DelEnum.DELETE.getDel())) {
                //应收款已经删除，则跳过不处理
                continue;
            }
            JSONObject updateData = new JSONObject();
            Long paymentId = entityExt.getId();
            JSONObject planData = entityExt.getData();
            Double finishAmount = commonHelp.handleAttrAmount(enumRealAmount.getAttr(), paymentIdToAmount, paymentId, planData, updateData);
            //已收小于0，则不能更新该应收款、且不能删除该应收款对应的回款单集合
            if(finishAmount < BasicConstant.ZERO_DOUBLE){
                //封装不能删除信息，并从delIdList、delNoList移除
                commonHelp.removeInfoAndAmountBack4DelError(true, I18nMessageUtil.getMessage(ErrorMessageConstant.NON_ZERO_CONTRACT_PAYMENT_AMOUNT), errorTypeSet, errorDataSet, pidSheetNoListMap, pidSheetIdListMap, delIdList, delNoList, paymentId, sheetDeleteHandleRelateDTO);
                continue;
            }
            double unAmount = commonHelp.handleAttrAmount(enumUnAmount.getAttr(), paymentIdToUnAmount, paymentId, planData, updateData);
            //未收小于0，则不能更新该应收款、且不能删除该应收款对应的回款单集合
            if(unAmount < BasicConstant.ZERO_DOUBLE){
                //封装不能删除信息，并从delIdList、delNoList移除
                commonHelp.removeInfoAndAmountBack4DelError(true, I18nMessageUtil.getMessage(ErrorMessageConstant.NON_ZERO_CONTRACT_PAYMENT_AMOUNT_UN), errorTypeSet, errorDataSet, pidSheetNoListMap, pidSheetIdListMap, delIdList, delNoList, paymentId, sheetDeleteHandleRelateDTO);
                continue;
            }
            double badAmount = commonHelp.handleAttrAmount(enumBadAmount.getAttr(), paymentIdToBad, paymentId, planData, updateData);
            //坏账小于0，则不能更新该应收款、且不能删除该应收款对应的回款单集合
            if(badAmount < BasicConstant.ZERO_DOUBLE){
                //封装不能删除信息，并从delIdList、delNoList移除
                commonHelp.removeInfoAndAmountBack4DelError(true, I18nMessageUtil.getMessage(ErrorMessageConstant.NON_ZERO_CONTRACT_PAYMENT_AMOUNT_BAD), errorTypeSet, errorDataSet, pidSheetNoListMap, pidSheetIdListMap, delIdList, delNoList, paymentId, sheetDeleteHandleRelateDTO);
                continue;
            }
            if (updateData.size() == 0) {
                //已收、未收、坏账金额都没变动
                continue;
            }
            //处理其回款时间
            Long realPayTime = 0L;
            List<PaasFormDataEntityExt> sheetList = sheetMap.get(paymentId);
            int hasRed = 0;
            if (CollectionUtils.isNotEmpty(sheetList)) {
                for (PaasFormDataEntity sheet : sheetList) {
                    JSONObject data = sheet.getData();
                    Long sheetPaymentTime = data.getLong(enumSheetPaymentTime.getAttr());
                    String paymentSheetType = data.getString(PaymentSheetEnum.PAYMENT_SHEET_TYPE.getAttr());
                    if (realPayTime < sheetPaymentTime && PaymentSheetTypeEnum.isWriteOff(paymentSheetType)) {
                        realPayTime = sheetPaymentTime;
                    }
                    if (PaymentSheetTypeEnum.isRed(paymentSheetType)) {
                        hasRed = 1;
                    }
                }
            }
            updateData.put(PaymentEnum.REAL_PAY_TIME.getAttr(), realPayTime);
            updateData.put(PaymentEnum.HAS_RED.getAttr(), hasRed);
            //设置应收款的状态
            Double planAmount = planData.getDoubleValue(PaymentEnum.AMOUNT.getAttr());
            //红冲应收金额
            Double redAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(planData, PaymentEnum.RED_AMOUNT.getAttr(), 0D);
            String planStatus = handleStatus(planAmount, unAmount, badAmount, redAmount);
            updateData.put(PaymentEnum.STATUS.getAttr(), planStatus);
            UpdateDataEntity updateDataEntity = ExplainUtil.getUpdateData(paymentId, updateData, corpid);
            updateList.add(updateDataEntity);
        }
        return updateList;
    }

    @Override
    public String handleStatus(Double planAmount, Double unAmount, Double badAmount, Double redAmount) {
        return payAndPaymentSheetHelp.handleStatus(planAmount, unAmount, badAmount, redAmount);
    }

    /**
     * 处理应收款的已收、未收、回款状态：回款金额增加的情况（已核销、预收款核销、红冲-需确保金额为负数）
     * 注：坏账的优先级最高，如果有坏账金额，则回款状态要么是坏账、要么是部分坏账
     * @param isBadFlag true坏账，false非坏账。当是坏账时，应收款的状态直接置为坏账
     * @param value 新传入的回款金额
     * @param updateData 要更新的data
     * @param planAmount 计划内的回款金额
     * @param planRealAmount 计划内的已收金额
     * @param unAmount 计划内的未收金额
     * @param badAmount 坏账金额
     * @param redAmount 红冲应收金额
     * @author zcp
     * @date 19/11/23 023 15:22
     * @update 19/11/23 023 15:22
     * @since v1.0
     * @version v1.0
     */
    private void handlePlanAmountStatus4Add(boolean isBadFlag, Double value, JSONObject updateData, Double planAmount, Double planRealAmount, Double unAmount, Double badAmount, Double redAmount) {
        //未收减去value，如果value为负数(红冲回款单)，则为加
        unAmount = Arith.sub(unAmount, value);
        if (isBadFlag) {
            //原坏账金额增加上新的坏账金额(其实不加也没问题，因为坏账只能一次性全部坏完，不存在再坏账一次)
            badAmount = Arith.add(badAmount, value);
            updateData.put(PaymentEnum.BAD_AMOUNT.getAttr(), value);
        } else {
            //已收加上amount（坏账不需要加实收：坏账是坏的未收，只对未收金额减去坏账金额即可）
            value = Arith.add(planRealAmount, value);
            updateData.put(REAL_AMOUNT.getAttr(), value);
        }
        String planStatus = handleStatus(planAmount, unAmount, badAmount, redAmount);
        updateData.put(PaymentEnum.STATUS.getAttr(), planStatus);
        updateData.put(PaymentEnum.UN_AMOUNT.getAttr(), unAmount);
    }

    /**
     * 除了计算总的未收/已收金额，还要处理封装明细-按顺序封装明细内所有东西：签订人、金额、合同名、应收款名等
     * 注：最后封装的明细排序规则为：（1）第一层按照前端传入的合同id顺序（dataIdList的顺序）；（2）第二层内层按照应收款预计回款时间升序-红冲则直接按照原单的明细进行渲染
     * @param isRedFlag 是否红冲，如果红冲则读取关联原始回款单相关及其子单（红冲预收款不会关联合同和应收款，不会调用该接口）；否则读取应收款的未收款
     * @param sheetAmountDetailGetDTO 获取回款单明细dto
     * @param dataIdList 合同id集合
     * @param paymentEnum 未收/实收字段
     * @param contractEnum 未收/已收字段
     * @param corpid 公司id
     * @return SheetAmountDetailGetVO
     * @throws XbbException
     * @author zcp
     * @date 19/12/11 011 21:11
     * @update 19/12/11 011 21:11
     * @since v1.0
     * @version v1.0
     */
    private SheetAmountDetailGetVO getResult4AmountDetail(String corpid, boolean isRedFlag, SheetAmountDetailGetDTO sheetAmountDetailGetDTO, List<Long> dataIdList, PaymentEnum paymentEnum, ContractEnum contractEnum) throws XbbException {
        //封装查询应收款（未收或已收）的条件，如果是红冲的，只需要获得关联的原始回款单
        AmountDetailGetPojo amountDetailGetPojo = getPaymentAmountDetailGetPojo(isRedFlag, sheetAmountDetailGetDTO);
        SheetAmountDetailGetVO sheetAmountDetailGetVO = new SheetAmountDetailGetVO();
        //合同id-该合同的应收款/回款单list（把同一个合同的应收款/回款单放到一起）
        Map<Long, List<JSONObject>> resultMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if (isRedFlag) {
            //创建红冲回款单，则只需读取到关联原始回款单，及其子单，然后明细通过其本身或子单进行渲染（只能红冲原单的已收）
            PaasFormDataEntityExt linkSheetEntity = amountDetailGetPojo.getLinkSheetEntity();
            //确保每个数据关联的合同、应收款都是一条（因为sheetList内只塞入子、及无子的回款单，而这类回款单都是只关联一个）
            List<PaasFormDataEntityExt> sheetList = new ArrayList<>();
            if (Objects.equals(linkSheetEntity.getAlone(), SheetAloneEnum.PARENT.getCode())) {
                //查询出所有子回款单
                sheetList.addAll(fundHelp.getChildEsDataListByParentUuid(IndexTypeEnum.IDX_SAAS_PAYMENT_SHEET, corpid, linkSheetEntity.getUuid(), null));
            } else {
                //无父子回款单则塞入本身
                sheetList.add(linkSheetEntity);
            }
            /**
             key：红冲回款单的合同id_应收款id
             value：红冲单据的金额
             */
            Map<String, Double> redCidPidAmountMap = paymentSheetService.handleRedSheetsBySheet(corpid, sheetAmountDetailGetDTO.getLinkPreId(), amountDetailGetPojo);
            Set<String> belongUserSet = new HashSet<>();
            for (PaasFormDataEntityExt entityExt : sheetList) {
                JSONArray belongArr = FastJsonHelper.getJsonArrOrDefaultFromFormData(entityExt.getData(), PaymentSheetEnum.BELONG_ID.getAttr(), new JSONArray());
                if (belongArr.size() > 0) {
                    List<String> belongList = belongArr.toJavaList(String.class);
                    belongUserSet.addAll(belongList);
                }
            }
            //归属人userId-归属人姓名
            Map<String, String> belongNameMap = commonHelp.getUserNameMapByIds(corpid, belongUserSet);
            for (PaasFormDataEntityExt entityExt : sheetList) {
                JSONObject data = entityExt.getData();
                String paymentSheetType = FastJsonHelper.getStringFromFormData(data, PaymentSheetEnum.PAYMENT_SHEET_TYPE.getAttr());
                JSONArray idArr = FastJsonHelper.getJsonArrFromFormData(data, PaymentSheetEnum.CONTRACT.getAttr());
                if (idArr == null || idArr.isEmpty()) {
                    continue;
                }
                JSONArray contractNoArr = FastJsonHelper.getJsonArrOrDefaultFromFormData(data, PaymentSheetEnum.CONTRACT_LINK_TEXT.getAttr(), new JSONArray());
                //都是一条（因为sheetList内只塞入子、及无子的回款单，而这类回款单都是只关联一个）
                Long contractId = idArr.getLong(0);
                String contractSerialNo = (contractNoArr.size() <= 0) ? "" : contractNoArr.getString(0);
                JSONArray belongArr = FastJsonHelper.getJsonArrOrDefaultFromFormData(data, PaymentSheetEnum.BELONG_ID.getAttr(), new JSONArray());
                //红冲回款单直接用原单的归属人
                String belongUserId = (belongArr.size() <= 0)? "": belongArr.getString(0);
                String belongName = belongNameMap.getOrDefault(belongUserId, "");
                //应收款信息
                List<Long> pidList = FastJsonHelper.getJsonArrOrDefaultFromFormData(data, PaymentSheetEnum.PAYMENT.getAttr(), new JSONArray()).toJavaList(Long.class);
                List<IdNamePojo> paymentInfo = null;
                String key = contractId + "";
                if (pidList.size() > 0) {
                    Long paymentId = pidList.get(0);
                    key += "_" + paymentId;
                    JSONArray nameArr = FastJsonHelper.getJsonArrFromFormData(data, PaymentSheetEnum.PAYMENT_LINK_TEXT.getAttr());
                    String paymentSerialNo = nameArr.getString(0);
                    paymentInfo = Collections.singletonList(new IdNamePojo(paymentId, paymentSerialNo));
                }
                double sheetAmount = FundHelp.getSheetAmount4PaymentSheet(data, paymentSheetType);
                //关联了合同、应收款的明细红冲金额，此时为负值
                Double sheetRedAmount = redCidPidAmountMap.getOrDefault(key, 0D);
                Double left = Arith.add(sheetAmount, sheetRedAmount);
                if (left == 0) {
                    continue;
                }
                JSONObject jsonObject = sheetAmountDetailGetVO.formatInfo(contractId, contractSerialNo, belongUserId, belongName, paymentInfo, left, left);
                List<JSONObject> list = resultMap.getOrDefault(contractId, new ArrayList<>());
                list.add(jsonObject);
                resultMap.put(contractId, list);
            }
            //最后封装的明细排序规则为：按照前端传入的合同id顺序（dataIdList的顺序）
            List<JSONObject> list = new ArrayList<>();
            for (Long contractId : dataIdList) {
                if (resultMap.get(contractId) != null) {
                    list.addAll(resultMap.get(contractId));
                }
            }
            fundHelp.subRedAmount(XbbRefTypeEnum.PAYMENT_SHEET, sheetAmountDetailGetVO, amountDetailGetPojo);
            sheetAmountDetailGetVO.setList(list);
        } else {
            //非红冲，则读取应收款的未收
            //应收款排序，内部排序方法需要用到explainMap
            PaasFormExplainEntity paasFormExplainEntity = paasFormExplainModel.getByBusinessType4Distributor(RedundantTemplateTypeEnum.PAYMENT.getCode(), corpid, sheetAmountDetailGetDTO.getDistributorMark());
            if (Objects.isNull(paasFormExplainEntity)) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_EXPLAIN_NOT_EXIST);
            }
            //排序字段：预计回款时间升序
            Map<String, String> sortMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            CompanyConfigEntity entity = companyConfigModel.getByConfigAlias(CompanyConfigEnum.WRITE_OFF_RULE.getAlias(), corpid);
            //FundSetDTO.sort 0：预计回款时间正序   1：预计回款时间倒序
            String sort = Objects.isNull(entity) || Objects.equals(entity.getConfigValue(), BasicConstant.ZERO_STRING) ? SortOrder.ASC.toString() : SortOrder.DESC.toString();
            sortMap.put("field", PaymentEnum.ESTIMATE_TIME.getAttr());
            sortMap.put("sort", sort);
            Map<String, FieldAttrEntity> explainMap = ExplainUtil.getExplainMap(paasFormExplainEntity.getExplains(), null);
            //得到应收款（未收/已收）查询结果：需对计划排序，因此需要explainMap、sortMap
            List<PaasFormDataEntityExt> planList = getPlanList4AmountDetailGet(amountDetailGetPojo, sheetAmountDetailGetDTO, explainMap, sortMap);
            //合同id-签订人userId
            Map<Long, String> cidSignPersonMap = new HashMap<>(dataIdList.size());
            //合同id-合同信息
            Map<Long, PaasFormDataEntityExt> cidMap = new HashMap<>(dataIdList.size());
            //签订人userId-签订人姓名
            Map<String, String> signNameMap = handleContractInfo(corpid, dataIdList, cidSignPersonMap, cidMap);
            String attrPlan = paymentEnum.getAttr();
            String attrContract = contractEnum.getAttr();
            String attrContract4Plan = PaymentEnum.CONTRACT.getAttr();
            //封装最终结果：（1）第一层按照前端传入的采购合同id顺序（dataIdList的顺序）；（2）第二层内层按照付款计划预计付款时间升序-红冲则直接按照原单的明细进行渲染
            fundHelp.formatDetailResult(true, sheetAmountDetailGetVO, dataIdList, resultMap, planList, cidMap, cidSignPersonMap, signNameMap, attrPlan, attrContract, attrContract4Plan);
        }
        return sheetAmountDetailGetVO;
    }

    /**
     * 只计算总的未收/已收金额即可，不用封装明细，但是要从每条应收款内求和得到已收/未收总额（回款单保存验证金额时，需要获取总金额进行数值校验）
     * @param isRedFlag 是否红冲，如果红冲则读取关联原始回款单相关（红冲预收款不会关联合同和应收款，不会调用该接口）
     * @param sheetAmountDetailGetDTO 获取回款单明细dto
     * @param dataIdList 合同id集合
     * @param paymentEnum 未收/实收字段
     * @param contractEnum 未收/已收字段
     * @param corpid 公司id
     * @return SheetAmountDetailGetVO
     * @throws XbbException
     * @author zcp
     * @date 19/12/11 011 21:23
     * @update 19/12/11 011 21:23
     * @since v1.0
     * @version v1.0
     */
    private SheetAmountDetailGetVO getResult4AmountDetailSum(boolean isRedFlag, SheetAmountDetailGetDTO sheetAmountDetailGetDTO, List<Long> dataIdList, PaymentEnum paymentEnum, ContractEnum contractEnum, String corpid) throws XbbException {
        SheetAmountDetailGetVO sheetAmountDetailGetVO = new SheetAmountDetailGetVO();
        //封装查询应收款（未收或已收）的条件，如果是红冲的，还需要获得关联的原始回款单
        AmountDetailGetPojo amountDetailGetPojo = getPaymentAmountDetailGetPojo(isRedFlag, sheetAmountDetailGetDTO);
        if (isRedFlag) {
            double redAmount = paymentSheetService.sumRedAmountBySheet(corpid, sheetAmountDetailGetDTO.getLinkPreId());
            amountDetailGetPojo.setRedAmount(redAmount);
            fundHelp.subRedAmount(XbbRefTypeEnum.PAYMENT_SHEET, sheetAmountDetailGetVO, amountDetailGetPojo);
        } else {
            // 得到应收款（未收/已收）查询结果：只求总的未收/已收，则无需排序，因此explainMap、sortMap都传null
            List<PaasFormDataEntityExt> planList = getPlanList4AmountDetailGet(amountDetailGetPojo, sheetAmountDetailGetDTO, null, null);
            //拥有应收款的合同id集合
            List<Long> hasPaymentCids = new ArrayList<>();
            Double sumAmount = 0D;
            for (PaasFormDataEntityExt entityExt : planList) {
                JSONObject data = entityExt.getData();
                Long contractId = data.getLongValue(PaymentEnum.CONTRACT.getAttr());
                hasPaymentCids.add(contractId);
                //已收或未收金额
                Double amount = getDoubleOrDefaultFromFormData(data, paymentEnum.getAttr(), 0D);
                sumAmount = Arith.add(sumAmount, amount);
            }
            //移除所有有应收款的合同ids，剩余无应收款的合同ids
            dataIdList.removeAll(hasPaymentCids);
            if (dataIdList.size() > 0) {
                List<String> fieldList = Arrays.asList(ContractEnum.getAttrConnectData(ContractEnum.AMOUNT), ContractEnum.getAttrConnectData(ContractEnum.FINISH_AMOUNT), ContractEnum.getAttrConnectData(ContractEnum.UN_FINISH_AMOUNT));
                List<PaasFormDataEntityExt> contracts = formHelp.getFormListByIds4All(corpid, IndexTypeEnum.IDX_SAAS_CONTRACT, dataIdList, fieldList);
                for (PaasFormDataEntityExt entityExt : contracts) {
                    //已收或未收金额
                    Double amount = getDoubleOrDefaultFromFormData(entityExt.getData(), contractEnum.getAttr(), 0D);
                    sumAmount = Arith.add(sumAmount, amount);
                }
            }
            sheetAmountDetailGetVO.setSumAmount(sumAmount);
        }
        return sheetAmountDetailGetVO;
    }

    /**
     * 非红冲：则封装查询应收款（未收或已收）的条件
     * 红冲：还需要获得关联的原始回款单
     * @param isRedFlag 是否红冲，如果红冲则读取关联原始回款单相关（红冲预收款不会关联合同和应收款，不会调用该接口）；否则读取应收款的未收款
     * @param sheetAmountDetailGetDTO 获取回款单明细dto
     * @return AmountDetailGetPojo
     * @throws XbbException
     * @author zcp
     * @since v1.0
     * @version v1.0
     */
    private AmountDetailGetPojo getPaymentAmountDetailGetPojo(boolean isRedFlag, SheetAmountDetailGetDTO sheetAmountDetailGetDTO) throws XbbException {
        AmountDetailGetPojo amountDetailGetPojo = new AmountDetailGetPojo();
        List<ConditionsEntityExt> conditionList = new ArrayList<>();
        //计划状态处理（如果是红冲，还需要读取原单、及原单已红冲金额，用于计算原单可红冲金额）
        ConditionsEntityExt planStatus;
        String corpid = sheetAmountDetailGetDTO.getCorpid();
        if (isRedFlag) {
            //红冲回款单，则需要传入关联原始回款单（红冲预收款余额不需要关联原单，且也不会调用该接口
            Long linkPreId = sheetAmountDetailGetDTO.getLinkPreId();
            if (Objects.equals(linkPreId, null) || Objects.equals(linkPreId, BasicConstant.ZERO_LONG)) {
                throw new XbbException(PaymentErrorCodeEnum.API_ERROR_208040, PaymentErrorCodeEnum.API_ERROR_208040.getMsg(), XbbRefTypeEnum.PAYMENT_SHEET.getName());
            }
            //关联的原始回款单
            PaymentSheetEntityExt linkSheetEntity = paymentSheetModel.getByKey(linkPreId, corpid);
            if (Objects.isNull(linkSheetEntity) || Objects.equals(linkSheetEntity.getDel(), BasicConstant.ONE)) {
                throw new XbbException(PaymentErrorCodeEnum.API_ERROR_208045, PaymentErrorCodeEnum.API_ERROR_208045.getMsg(), XbbRefTypeEnum.PAYMENT_SHEET.getName());
            }
            amountDetailGetPojo.setLinkSheetEntity(linkSheetEntity);
            //读取已收、部分收款
            planStatus = new ConditionsEntityExt(PaymentEnum.STATUS.getAttr(), "", PaymentEnum.STATUS.getFieldType(), ConditionEnum.IN.getSymbol(), Arrays.asList(PaymentStatusEnum.RECEIVABLES.getCode(), PaymentStatusEnum.PARTIAL_RECEIPTS.getCode()));
        } else {
            //读取未收款、部分收款
            planStatus = new ConditionsEntityExt(PaymentEnum.STATUS.getAttr(), "", PaymentEnum.STATUS.getFieldType(), ConditionEnum.IN.getSymbol(), Arrays.asList(PaymentStatusEnum.UN_RECEIVABLES.getCode(), PaymentStatusEnum.PARTIAL_RECEIPTS.getCode()));
            //有未收金额的应收款，如果应收款的未收金额为0，则不能选择到应收款。因为创建回款单时要把应收款的未收款减少
            conditionList.add(new ConditionsEntityExt(PaymentEnum.UN_AMOUNT.getAttr(), "", PaymentEnum.UN_AMOUNT.getFieldType(), ConditionEnum.GREATERTHAN.getSymbol(), Collections.singletonList(BasicConstant.ZERO_DOUBLE)));
        }
        conditionList.add(planStatus);
        //塞入合同ids条件
        List<Object> contractIdList = new ArrayList<>(sheetAmountDetailGetDTO.getDataIdList());
        ConditionsEntityExt conditionsEntityExt = new ConditionsEntityExt(PaymentEnum.CONTRACT.getAttr(), "", PaymentEnum.CONTRACT.getFieldType(), ConditionEnum.IN.getSymbol(), contractIdList);
        conditionList.add(conditionsEntityExt);
        //paymentIdList为空，则返回合同关联的所有应收款（无计划则返回合同本身）；该值不为空，则只展示该paymentIdList内的应收款
        List<Long> paymentIdList = sheetAmountDetailGetDTO.getPaymentIdList();
        if (sheetAmountDetailGetDTO.getEmptyFilterFlag()) {
            if (paymentIdList == null) {
                paymentIdList = new ArrayList<>();
            }
            paymentIdList.add(-1L);
        }
        if (CollectionUtils.isNotEmpty(paymentIdList)) {
            ConditionsEntityExt paymentIdConditions = new ConditionsEntityExt(BasicConstant.ID, "", FieldTypeEnum.DATAID.getType(), ConditionEnum.IN.getSymbol(), new ArrayList<>(paymentIdList));
            conditionList.add(paymentIdConditions);
        }
        amountDetailGetPojo.setConditionList(conditionList);
        return amountDetailGetPojo;
    }

    /**
     * 根据关联id和条件获取数据
     * @param amountDetailGetPojo 获取金额明细时需要用到的条件、原单信息pojo
     * @param sheetAmountDetailGetDTO dto
     * @param explainMap 解释map（排序时用到）
     * @param sortMap 排序map
     * @return AmountDetailGetPojo
     * @throws XbbException
     * @author zcp
     * @since v1.0
     * @version v1.0
     */
    private List<PaasFormDataEntityExt> getPlanList4AmountDetailGet(AmountDetailGetPojo amountDetailGetPojo, SheetAmountDetailGetDTO sheetAmountDetailGetDTO, Map<String, FieldAttrEntity> explainMap, Map<String, String> sortMap) throws XbbException {
        //查询出部分字段（其他id、dataId等字段内部会强制加上去，无需重复置入）
        List<String> fieldList = Arrays.asList(PaymentEnum.CONTRACT.getAttr(), PaymentEnum.UN_AMOUNT.getAttr(), REAL_AMOUNT.getAttr());
        FormDataListDTO formDataListDTO = new FormDataListDTO();
        BeanUtil.copyProperties(sheetAmountDetailGetDTO, formDataListDTO);
        formDataListDTO.setAppId(null);
        formDataListDTO.setFormId(null);
        formDataListDTO.setDel(DelEnum.NORMAL.getDel());
        formDataListDTO.setConditions(amountDetailGetPojo.getConditionList());
        formDataListDTO.setBusinessType(XbbRefTypeEnum.PAYMENT.getCode());
        formDataListDTO.setSortMap(sortMap);
        formDataListDTO.setExplainMap(explainMap);
        formDataListDTO.setFieldList(fieldList);
        formDataListDTO.setSearchSubForm(false);
        IndexTypeEnum indexTypeEnum = indexTypeModel.getIndexType(formDataListDTO.getCorpid(), formDataListDTO.getBusinessType(), formDataListDTO.getSaasMark());
        PaasFormDataEsListVO paasFormDataEsListVO = paasFormDataEsModel.list(formDataListDTO, indexTypeEnum);
        PageHelper pageHelper = paasFormDataEsListVO.getPageHelper();
        if (pageHelper.getRowsCount() > SizeConstant.PAGE_SIZE) {
            //查询合同下的应收款时，限制只能查询1w条
            throw new XbbException(PaymentErrorCodeEnum.API_ERROR_208030, PaymentErrorCodeEnum.API_ERROR_208030.getMsg(), SizeConstant.PAGE_SIZE);
        }
        return paasFormDataEsListVO.getPaasFormDataESList();
    }

    /**
     * 获取所有的红冲应收款
     *
     * @param formDataListDTO
     * @return
     * @throws XbbException
     * @author chenshan
     * @data 2019/12/13 11:21
     */
    @Override
    public PaasFormDataEsListVO getPaymentList(FormDataListDTO formDataListDTO) throws XbbException {
        formDataListDTO.setSearchSubForm(false);
        IndexTypeEnum indexTypeEnum = indexTypeModel.getIndexType(formDataListDTO.getCorpid(), formDataListDTO.getBusinessType(), formDataListDTO.getSaasMark());
        return  paasFormDataEsModel.list(formDataListDTO, indexTypeEnum);
    }

    @Override
    public void updateBatchLabelAttr(AddLabelDTO addLabelDTO, List<PaasFormDataEntityExt> addBatchList, Boolean addOrDelete) throws XbbException {
        PaymentUpdateBatchDTO paymentUpdateBatchDTO = new PaymentUpdateBatchDTO();
        BeanUtil.copyProperties(addLabelDTO, paymentUpdateBatchDTO);
        List<PaymentUpdateDTO> paymentList = new ArrayList<>();
        addBatchList.forEach(item ->{
            PaymentUpdateDTO paymentUpdateDTO = new PaymentUpdateDTO();
            paymentUpdateDTO.setData(item.getData());
            paymentUpdateDTO.setId(item.getId());
            paymentList.add(paymentUpdateDTO);
        });
        paymentUpdateBatchDTO.setPaymenrUpdateList(paymentList);
        updateBatch(paymentUpdateBatchDTO);

    }

    @Override
    public Map<Long,Double> getReceivablesAmount(String corpid,IndexTypeEnum indexTypeEnum,List<Long> sourceId) throws XbbException{
        Double sumAmount = 0D;
        String esData = StringConstant.JSON_DATA + StringConstant.POINT;
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termsQuery(esData+PaymentEnum.CONTRACT.getAttr(),sourceId));
        boolQueryBuilder.filter(termQuery(StringConstant.CORPID + StringConstant.POINT + StringConstant.KEY_WORD , corpid));
        boolQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
        List<String> fieldList = new ArrayList<>();
        fieldList.add(PaymentEnum.getAttrConnectData(PaymentEnum.AMOUNT));
        fieldList.add(PaymentEnum.getAttrConnectData(PaymentEnum.CONTRACT));
        List<PaasFormDataEntityExt> paasFormDataEntityExts = esHelper.findByScroll(indexTypeEnum,boolQueryBuilder,PaasFormDataEntityExt.class,fieldList);
        Map<Long,Double> map = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if(CollectionsUtil.isNotEmpty(paasFormDataEntityExts)){
            for(PaasFormDataEntityExt paasFormDataEntityExt : paasFormDataEntityExts){
               JSONObject data = paasFormDataEntityExt.getData();
               Long contractId = FastJsonHelper.getLongOrDefaultFromFormData(data,PaymentEnum.CONTRACT.getAttr(),0L);
               Double amount = FastJsonHelper.getDoubleOrDefaultFromFormData(data,PaymentEnum.AMOUNT.getAttr(),0D);
               saasSaveHelp.addMapNormal(map,contractId,amount);
            }
        }
        return map;
    }

    @Override
    public List<PaasFormDataEntityExt> checkCanDelPayment(String corpid, XbbRefTypeEnum xbbRefTypeEnum, List<Long> dataIdList) throws XbbException {
        List<PaasFormDataEntityExt> paasFormDataEntityExts = getReceivablesBySourceIdIn(corpid, xbbRefTypeEnum.getCode(), dataIdList);
        if (!CollectionsUtil.isEmpty(paasFormDataEntityExts)){
            //这时候已经代表回款计划关联应收款，这时候需要判断应收款是不是关联回款单,根据应收款的实收金额或者坏账金额
            for (PaasFormDataEntityExt paasFormDataEntityExt : paasFormDataEntityExts){
                JSONObject jsonObject = paasFormDataEntityExt.getData();
                Double realAmount  = FastJsonHelper.getDoubleOrDefaultFromFormData(jsonObject, PaymentEnum.REAL_AMOUNT.getAttr(), 0D);
                Double badAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(jsonObject, PaymentEnum.BAD_AMOUNT.getAttr(), 0D);
                String sourceSerialNo = FastJsonHelper.getStringOrDefaultFromFormData(jsonObject, PaymentEnum.SOURCE_LINK_TEXT.getAttr(),"");
                if (realAmount > 0 || badAmount > 0){
                    throw new XbbException(PayPlanErrorCodeEnum.API_ERROR_247005, String.format(PayPlanErrorCodeEnum.API_ERROR_247005.getMsg(), sourceSerialNo, xbbRefTypeEnum.getName()));
                }
            }
        }
        return paasFormDataEntityExts;
    }

    @Override
    public List<PaasFormDataEntityExt> getReceivablesBySourceIdIn(String corpid, Integer sourceRefType, List<Long> sourceIdIn) throws XbbException{
        String esData = StringConstant.JSON_DATA + StringConstant.POINT;
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery(esData + PaymentEnum.SOURCE_REF_TYPE.getAttr(), sourceRefType));
        boolQueryBuilder.filter(termsQuery(esData+PaymentEnum.SOURCE.getAttr(),sourceIdIn));
        boolQueryBuilder.filter(termQuery(StringConstant.CORPID + StringConstant.POINT + StringConstant.KEY_WORD , corpid));
        boolQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
        List<String> fieldList = new ArrayList<>();
        fieldList.add(PaymentEnum.getAttrConnectData(PaymentEnum.REAL_AMOUNT));
        fieldList.add(PaymentEnum.getAttrConnectData(PaymentEnum.BAD_AMOUNT));
        fieldList.add(PaymentEnum.getAttrConnectData(PaymentEnum.RED_AMOUNT));
        fieldList.add(PaymentEnum.getAttrConnectData(PaymentEnum.SOURCE));
        fieldList.add(PaymentEnum.getAttrConnectData(PaymentEnum.SOURCE_LINK_TEXT));
        fieldList.add(BusinessConstant.ID);
        fieldList.add(PaymentEnum.PAYMENT_NO.getAttr());
        List<PaasFormDataEntityExt> paasFormDataEntityExts = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_PAYMENT, boolQueryBuilder, PaasFormDataEntityExt.class, fieldList);
        return paasFormDataEntityExts;
    }

    @Override
    public List<PaasFormDataEntityExt> getEntityByReceivablesOriginIdIn(String corpid,IndexTypeEnum indexTypeEnum,List<Long> receivablesOriginIdIn) throws XbbException{
        String esData = StringConstant.JSON_DATA + StringConstant.POINT;

        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termsQuery(esData+PaymentEnum.RECEIVABLES_ORIGIN_ID.getAttr(),receivablesOriginIdIn));
        boolQueryBuilder.filter(termQuery(StringConstant.CORPID + StringConstant.POINT + StringConstant.KEY_WORD , corpid));
        boolQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
        List<String> fieldList = new ArrayList<>();
        fieldList.add(PaymentEnum.getAttrConnectData(PaymentEnum.RED_AMOUNT));
        List<PaasFormDataEntityExt> paasFormDataEntityExts = esHelper.findByScroll(indexTypeEnum,boolQueryBuilder,PaasFormDataEntityExt.class,fieldList);
        return paasFormDataEntityExts;
    }

    @Override
    public void afterSaveForWorkflow(SaasFormSaveDTO saasFormSaveDTO) throws XbbException {
        String corpid = saasFormSaveDTO.getCorpid();
        PaasFormDataEntity newPaasFormDataEntity = saasFormSaveDTO.getNewPaasFormDataEntity();
        Long dataId = newPaasFormDataEntity.getId();
        JSONObject newData = saasFormSaveDTO.getNewData();
        JSONObject oldData = saasFormSaveDTO.getOldData();

        // 团队处理
        Long customerId = FastJsonHelper.getLongOrDefaultFromFormData(newData, PaymentEnum.CUSTOMER.getAttr(),0L);
        Long contractId = FastJsonHelper.getLongOrDefaultFromFormData(newData,PaymentEnum.CONTRACT.getAttr(),0L);
        userTeamService.createPaymentUser(corpid,customerId,contractId, Collections.singletonList(dataId), PaymentLinkTypeEnum.CONTRACT.getCode(),false);

    }

    @Override
    public void afterSaveForUpdateWorkflow(SaasFormSaveDTO saasFormSaveDTO) {

    }

    /**
     * 上游销项发票编号改了，下游应收款中的来源单据也需要同步修改。资金这边有发票产生应收的模式
     *
     * @param corpid
     * @param dataId
     * @param invoiceSerialNo
     */
    @Override
    public void dataConsistencyUpdateInvoice(String corpid, Long dataId, String invoiceSerialNo) throws XbbException{
        try {
            BoolQueryBuilder filter = boolQuery()
                    .filter(termQuery("corpid.keyword", corpid))
                    .filter(termQuery("del", 0))
                    .filter(termQuery(PaymentEnum.getEsAttr4Keyword(PaymentEnum.SOURCE), dataId))
                    .filter(termQuery(PaymentEnum.getEsAttr4Keyword(PaymentEnum.SOURCE_REF_TYPE), XbbRefTypeEnum.INVOICE.getCode()));
            List<String> fieldList = new ArrayList<>();
            fieldList.add(FieldTypeEnum.DATAID.getAlias());
            List<PaasFormDataEntityExt> esEntities = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_PAYMENT, filter, PaasFormDataEntityExt.class, fieldList);
            Set<Long> ids = new HashSet<>();
            for (PaasFormDataEntityExt esEntity : esEntities) {
                ids.add(esEntity.getDataId());
            }
            Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            param.put("corpid", corpid);
            param.put("idIn", ids);
            param.put("del", 0);
            List<PaymentEntityExt> paymentEntityExts = paymentModel.findEntitys(param);
            if (Objects.nonNull(paymentEntityExts) && !paymentEntityExts.isEmpty()) {
                List<PaymentUpdateDTO> paymentUpdateDTOList = new ArrayList<>();
                for (PaymentEntityExt entityExt : paymentEntityExts) {
                    JSONObject oldData = entityExt.getData();
                    if (oldData == null) {
                        continue;
                    }
                    PaymentUpdateDTO paymentUpdateDTO = new PaymentUpdateDTO();
                    paymentUpdateDTO.setId(entityExt.getId());
                    JSONObject data = new JSONObject();
                    data.put(PaymentEnum.SOURCE_LINK_TEXT.getAttr(), invoiceSerialNo);
                    paymentUpdateDTO.setData(data);
                    paymentUpdateDTOList.add(paymentUpdateDTO);
                }
                PaymentUpdateBatchDTO paymentUpdateBatchDTO = new PaymentUpdateBatchDTO();
                paymentUpdateBatchDTO.setCorpid(corpid);
                paymentUpdateBatchDTO.setPaymenrUpdateList(paymentUpdateDTOList);
                updateBatch(paymentUpdateBatchDTO);
            }
        } catch (Exception e) {
            LOG.error("paymentServiceImpl.dataConsistencyUpdatePayment fail， corpid=" + corpid + " invoiceId=" + dataId + "  invoiceNo=" + invoiceSerialNo, e);
        }
    }

    @Override
    public void dataConsistencyUpdateContractOutStock(String corpid, Long dataId, String contractOutStockSerialNo) throws XbbException{
        try {
            BoolQueryBuilder filter = boolQuery()
                    .filter(termQuery("corpid.keyword", corpid))
                    .filter(termQuery("del", 0))
                    .filter(termQuery(PaymentEnum.getEsAttr4Keyword(PaymentEnum.SOURCE), dataId))
                    .filter(termQuery(PaymentEnum.getEsAttr4Keyword(PaymentEnum.SOURCE_REF_TYPE), XbbRefTypeEnum.CONTRACT_OUTSTOCK.getCode()));
            List<String> fieldList = new ArrayList<>();
            fieldList.add(FieldTypeEnum.DATAID.getAlias());
            List<PaasFormDataEntityExt> esEntities = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_PAYMENT, filter, PaasFormDataEntityExt.class, fieldList);
            Set<Long> ids = new HashSet<>();
            for (PaasFormDataEntityExt esEntity : esEntities) {
                ids.add(esEntity.getDataId());
            }
            Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            param.put("corpid", corpid);
            param.put("idIn", ids);
            param.put("del", 0);
            List<PaymentEntityExt> paymentEntityExts = paymentModel.findEntitys(param);
            if (Objects.nonNull(paymentEntityExts) && !paymentEntityExts.isEmpty()) {
                List<PaymentUpdateDTO> paymentUpdateDTOList = new ArrayList<>();
                for (PaymentEntityExt entityExt : paymentEntityExts) {
                    JSONObject oldData = entityExt.getData();
                    if (oldData == null) {
                        continue;
                    }
                    PaymentUpdateDTO paymentUpdateDTO = new PaymentUpdateDTO();
                    paymentUpdateDTO.setId(entityExt.getId());
                    JSONObject data = new JSONObject();
                    data.put(PaymentEnum.SOURCE_LINK_TEXT.getAttr(), contractOutStockSerialNo);
                    paymentUpdateDTO.setData(data);
                    paymentUpdateDTOList.add(paymentUpdateDTO);
                }
                PaymentUpdateBatchDTO paymentUpdateBatchDTO = new PaymentUpdateBatchDTO();
                paymentUpdateBatchDTO.setCorpid(corpid);
                paymentUpdateBatchDTO.setPaymenrUpdateList(paymentUpdateDTOList);
                updateBatch(paymentUpdateBatchDTO);
            }
        } catch (Exception e) {
            LOG.error("paymentServiceImpl.dataConsistencyUpdatePayment fail， corpid=" + corpid + " contractOutStockId=" + dataId + "  contractOutStockNo=" + contractOutStockSerialNo, e);
        }
    }
}
